xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 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.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl.
8 
9 #include "libANGLE/renderer/d3d/ProgramD3D.h"
10 
11 #include "common/MemoryBuffer.h"
12 #include "common/bitset_utils.h"
13 #include "common/string_utils.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Program.h"
17 #include "libANGLE/ProgramLinkedResources.h"
18 #include "libANGLE/Uniform.h"
19 #include "libANGLE/VertexArray.h"
20 #include "libANGLE/features.h"
21 #include "libANGLE/queryconversions.h"
22 #include "libANGLE/renderer/ContextImpl.h"
23 #include "libANGLE/renderer/d3d/ContextD3D.h"
24 #include "libANGLE/renderer/d3d/ShaderD3D.h"
25 #include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
26 #include "libANGLE/renderer/d3d/VertexDataManager.h"
27 #include "libANGLE/renderer/renderer_utils.h"
28 #include "libANGLE/trace.h"
29 
30 using namespace angle;
31 
32 namespace rx
33 {
34 namespace
35 {
HasFlatInterpolationVarying(const std::vector<sh::ShaderVariable> & varyings)36 bool HasFlatInterpolationVarying(const std::vector<sh::ShaderVariable> &varyings)
37 {
38     // Note: this assumes nested structs can only be packed with one interpolation.
39     for (const auto &varying : varyings)
40     {
41         if (varying.interpolation == sh::INTERPOLATION_FLAT)
42         {
43             return true;
44         }
45     }
46 
47     return false;
48 }
49 
FindFlatInterpolationVaryingPerShader(const gl::SharedCompiledShaderState & shader)50 bool FindFlatInterpolationVaryingPerShader(const gl::SharedCompiledShaderState &shader)
51 {
52     ASSERT(shader);
53     switch (shader->shaderType)
54     {
55         case gl::ShaderType::Vertex:
56             return HasFlatInterpolationVarying(shader->outputVaryings);
57         case gl::ShaderType::Fragment:
58             return HasFlatInterpolationVarying(shader->inputVaryings);
59         case gl::ShaderType::Geometry:
60             return HasFlatInterpolationVarying(shader->inputVaryings) ||
61                    HasFlatInterpolationVarying(shader->outputVaryings);
62         default:
63             UNREACHABLE();
64             return false;
65     }
66 }
67 
FindFlatInterpolationVarying(const gl::ShaderMap<gl::SharedCompiledShaderState> & shaders)68 bool FindFlatInterpolationVarying(const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders)
69 {
70     for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
71     {
72         const gl::SharedCompiledShaderState &shader = shaders[shaderType];
73         if (!shader)
74         {
75             continue;
76         }
77 
78         if (FindFlatInterpolationVaryingPerShader(shader))
79         {
80             return true;
81         }
82     }
83 
84     return false;
85 }
86 
87 class HLSLBlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
88 {
89   public:
makeEncoder()90     sh::BlockLayoutEncoder *makeEncoder() override
91     {
92         return new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
93     }
94 };
95 
96 // GetExecutableTask class
97 class GetExecutableTask : public LinkSubTask, public d3d::Context
98 {
99   public:
GetExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)100     GetExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
101         : mProgram(program), mExecutable(program->getExecutable()), mShader(shader)
102     {}
103     ~GetExecutableTask() override = default;
104 
getResult(const gl::Context * context,gl::InfoLog & infoLog)105     angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
106     {
107         ASSERT((mResult == angle::Result::Continue) == (mStoredHR == S_OK));
108 
109         ANGLE_TRY(checkTask(context, infoLog));
110 
111         // Append debug info
112         if (mShader && mShaderExecutable != nullptr)
113         {
114             mShader->appendDebugInfo(mShaderExecutable->getDebugInfo());
115         }
116 
117         return angle::Result::Continue;
118     }
119 
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)120     void handleResult(HRESULT hr,
121                       const char *message,
122                       const char *file,
123                       const char *function,
124                       unsigned int line) override
125     {
126         mStoredHR       = hr;
127         mStoredMessage  = message;
128         mStoredFile     = file;
129         mStoredFunction = function;
130         mStoredLine     = line;
131     }
132 
133   protected:
popError(d3d::Context * context)134     void popError(d3d::Context *context)
135     {
136         ASSERT(mStoredFile);
137         ASSERT(mStoredFunction);
138         context->handleResult(mStoredHR, mStoredMessage.c_str(), mStoredFile, mStoredFunction,
139                               mStoredLine);
140     }
141 
checkTask(const gl::Context * context,gl::InfoLog & infoLog)142     angle::Result checkTask(const gl::Context *context, gl::InfoLog &infoLog)
143     {
144         // Forward any logs
145         if (!mInfoLog.empty())
146         {
147             infoLog << mInfoLog.str();
148         }
149 
150         // Forward any errors
151         if (mResult != angle::Result::Continue)
152         {
153             ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
154             popError(contextD3D);
155             return angle::Result::Stop;
156         }
157 
158         return angle::Result::Continue;
159     }
160 
161     ProgramD3D *mProgram              = nullptr;
162     ProgramExecutableD3D *mExecutable = nullptr;
163     angle::Result mResult             = angle::Result::Continue;
164     gl::InfoLog mInfoLog;
165     ShaderExecutableD3D *mShaderExecutable = nullptr;
166     SharedCompiledShaderStateD3D mShader;
167 
168     // Error handling
169     HRESULT mStoredHR = S_OK;
170     std::string mStoredMessage;
171     const char *mStoredFile     = nullptr;
172     const char *mStoredFunction = nullptr;
173     unsigned int mStoredLine    = 0;
174 };
175 }  // anonymous namespace
176 
177 // ProgramD3DMetadata Implementation
ProgramD3DMetadata(RendererD3D * renderer,const gl::SharedCompiledShaderState & fragmentShader,const gl::ShaderMap<SharedCompiledShaderStateD3D> & attachedShaders,int shaderVersion)178 ProgramD3DMetadata::ProgramD3DMetadata(
179     RendererD3D *renderer,
180     const gl::SharedCompiledShaderState &fragmentShader,
181     const gl::ShaderMap<SharedCompiledShaderStateD3D> &attachedShaders,
182     int shaderVersion)
183     : mRendererMajorShaderModel(renderer->getMajorShaderModel()),
184       mShaderModelSuffix(renderer->getShaderModelSuffix()),
185       mUsesViewScale(renderer->presentPathFastEnabled()),
186       mCanSelectViewInVertexShader(renderer->canSelectViewInVertexShader()),
187       mFragmentShader(fragmentShader),
188       mAttachedShaders(attachedShaders),
189       mShaderVersion(shaderVersion)
190 {}
191 
192 ProgramD3DMetadata::~ProgramD3DMetadata() = default;
193 
getRendererMajorShaderModel() const194 int ProgramD3DMetadata::getRendererMajorShaderModel() const
195 {
196     return mRendererMajorShaderModel;
197 }
198 
usesBroadcast(const gl::Version & clientVersion) const199 bool ProgramD3DMetadata::usesBroadcast(const gl::Version &clientVersion) const
200 {
201     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
202     return shader && shader->usesFragColor && shader->usesMultipleRenderTargets &&
203            clientVersion.major < 3;
204 }
205 
usesSecondaryColor() const206 bool ProgramD3DMetadata::usesSecondaryColor() const
207 {
208     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
209     return shader && shader->usesSecondaryColor;
210 }
211 
getFragDepthUsage() const212 FragDepthUsage ProgramD3DMetadata::getFragDepthUsage() const
213 {
214     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
215     return shader ? shader->fragDepthUsage : FragDepthUsage::Unused;
216 }
217 
usesPointCoord() const218 bool ProgramD3DMetadata::usesPointCoord() const
219 {
220     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
221     return shader && shader->usesPointCoord;
222 }
223 
usesFragCoord() const224 bool ProgramD3DMetadata::usesFragCoord() const
225 {
226     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
227     return shader && shader->usesFragCoord;
228 }
229 
usesPointSize() const230 bool ProgramD3DMetadata::usesPointSize() const
231 {
232     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
233     return shader && shader->usesPointSize;
234 }
235 
usesInsertedPointCoordValue() const236 bool ProgramD3DMetadata::usesInsertedPointCoordValue() const
237 {
238     return usesPointCoord() && mRendererMajorShaderModel >= 4;
239 }
240 
usesViewScale() const241 bool ProgramD3DMetadata::usesViewScale() const
242 {
243     return mUsesViewScale;
244 }
245 
hasMultiviewEnabled() const246 bool ProgramD3DMetadata::hasMultiviewEnabled() const
247 {
248     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
249     return shader && shader->hasMultiviewEnabled;
250 }
251 
usesVertexID() const252 bool ProgramD3DMetadata::usesVertexID() const
253 {
254     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
255     return shader && shader->usesVertexID;
256 }
257 
usesViewID() const258 bool ProgramD3DMetadata::usesViewID() const
259 {
260     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
261     return shader && shader->usesViewID;
262 }
263 
canSelectViewInVertexShader() const264 bool ProgramD3DMetadata::canSelectViewInVertexShader() const
265 {
266     return mCanSelectViewInVertexShader;
267 }
268 
addsPointCoordToVertexShader() const269 bool ProgramD3DMetadata::addsPointCoordToVertexShader() const
270 {
271     // With a geometry shader, the app can render triangles or lines and reference
272     // gl_PointCoord in the fragment shader, requiring us to provide a placeholder value. For
273     // simplicity, we always add this to the vertex shader when the fragment shader
274     // references gl_PointCoord, even if we could skip it in the geometry shader.
275     return usesInsertedPointCoordValue();
276 }
277 
usesTransformFeedbackGLPosition() const278 bool ProgramD3DMetadata::usesTransformFeedbackGLPosition() const
279 {
280     // gl_Position only needs to be outputted from the vertex shader if transform feedback is
281     // active. This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from
282     // the vertex shader in this case. This saves us 1 output vector.
283     return !(mRendererMajorShaderModel >= 4 && mShaderModelSuffix != "");
284 }
285 
usesSystemValuePointSize() const286 bool ProgramD3DMetadata::usesSystemValuePointSize() const
287 {
288     return usesPointSize();
289 }
290 
usesMultipleFragmentOuts() const291 bool ProgramD3DMetadata::usesMultipleFragmentOuts() const
292 {
293     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
294     return shader && shader->usesMultipleRenderTargets;
295 }
296 
usesCustomOutVars() const297 bool ProgramD3DMetadata::usesCustomOutVars() const
298 {
299     return mShaderVersion >= 300;
300 }
301 
usesSampleMask() const302 bool ProgramD3DMetadata::usesSampleMask() const
303 {
304     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
305     return shader && shader->usesSampleMask;
306 }
307 
getFragmentShader() const308 const gl::SharedCompiledShaderState &ProgramD3DMetadata::getFragmentShader() const
309 {
310     return mFragmentShader;
311 }
312 
getClipDistanceArraySize() const313 uint8_t ProgramD3DMetadata::getClipDistanceArraySize() const
314 {
315     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
316     return shader ? shader->clipDistanceSize : 0;
317 }
318 
getCullDistanceArraySize() const319 uint8_t ProgramD3DMetadata::getCullDistanceArraySize() const
320 {
321     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
322     return shader ? shader->cullDistanceSize : 0;
323 }
324 
325 // ProgramD3D Implementation
326 
327 class ProgramD3D::GetVertexExecutableTask : public GetExecutableTask
328 {
329   public:
GetVertexExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)330     GetVertexExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
331         : GetExecutableTask(program, shader)
332     {}
333     ~GetVertexExecutableTask() override = default;
334 
operator ()()335     void operator()() override
336     {
337         ANGLE_TRACE_EVENT0("gpu.angle", "GetVertexExecutableTask::run");
338 
339         mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Vertex);
340         mResult = mExecutable->getVertexExecutableForCachedInputLayout(
341             this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
342     }
343 };
344 
345 class ProgramD3D::GetPixelExecutableTask : public GetExecutableTask
346 {
347   public:
GetPixelExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)348     GetPixelExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
349         : GetExecutableTask(program, shader)
350     {}
351     ~GetPixelExecutableTask() override = default;
352 
operator ()()353     void operator()() override
354     {
355         ANGLE_TRACE_EVENT0("gpu.angle", "GetPixelExecutableTask::run");
356         if (!mShader)
357         {
358             return;
359         }
360 
361         mExecutable->updateCachedOutputLayoutFromShader();
362         mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Fragment);
363         mResult = mExecutable->getPixelExecutableForCachedOutputLayout(
364             this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
365     }
366 };
367 
368 class ProgramD3D::GetGeometryExecutableTask : public GetExecutableTask
369 {
370   public:
GetGeometryExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader,const gl::Caps & caps,gl::ProvokingVertexConvention provokingVertex)371     GetGeometryExecutableTask(ProgramD3D *program,
372                               const SharedCompiledShaderStateD3D &shader,
373                               const gl::Caps &caps,
374                               gl::ProvokingVertexConvention provokingVertex)
375         : GetExecutableTask(program, shader), mCaps(caps), mProvokingVertex(provokingVertex)
376     {}
377     ~GetGeometryExecutableTask() override = default;
378 
operator ()()379     void operator()() override
380     {
381         ANGLE_TRACE_EVENT0("gpu.angle", "GetGeometryExecutableTask::run");
382         // Auto-generate the geometry shader here, if we expect to be using point rendering in
383         // D3D11.
384         if (mExecutable->usesGeometryShader(mProgram->mRenderer, mProvokingVertex,
385                                             gl::PrimitiveMode::Points))
386         {
387             mResult = mExecutable->getGeometryExecutableForPrimitiveType(
388                 this, mProgram->mRenderer, mCaps, mProvokingVertex, gl::PrimitiveMode::Points,
389                 &mShaderExecutable, &mInfoLog);
390         }
391     }
392 
393   private:
394     const gl::Caps &mCaps;
395     gl::ProvokingVertexConvention mProvokingVertex;
396 };
397 
398 class ProgramD3D::GetComputeExecutableTask : public GetExecutableTask
399 {
400   public:
GetComputeExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)401     GetComputeExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
402         : GetExecutableTask(program, shader)
403     {}
404     ~GetComputeExecutableTask() override = default;
405 
operator ()()406     void operator()() override
407     {
408         ANGLE_TRACE_EVENT0("gpu.angle", "GetComputeExecutableTask::run");
409 
410         mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Compute);
411         mResult = mExecutable->getComputeExecutableForImage2DBindLayout(
412             this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
413     }
414 };
415 
416 class ProgramD3D::LinkLoadTaskD3D : public d3d::Context, public LinkTask
417 {
418   public:
LinkLoadTaskD3D(ProgramD3D * program)419     LinkLoadTaskD3D(ProgramD3D *program) : mProgram(program), mExecutable(program->getExecutable())
420     {
421         ASSERT(mProgram);
422     }
423     ~LinkLoadTaskD3D() override = default;
424 
getResult(const gl::Context * context,gl::InfoLog & infoLog)425     angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
426     {
427         if (mStoredHR != S_OK)
428         {
429             GetImplAs<ContextD3D>(context)->handleResult(mStoredHR, mStoredMessage.c_str(),
430                                                          mStoredFile, mStoredFunction, mStoredLine);
431             return angle::Result::Stop;
432         }
433 
434         return angle::Result::Continue;
435     }
436 
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)437     void handleResult(HRESULT hr,
438                       const char *message,
439                       const char *file,
440                       const char *function,
441                       unsigned int line) override
442     {
443         mStoredHR       = hr;
444         mStoredMessage  = message;
445         mStoredFile     = file;
446         mStoredFunction = function;
447         mStoredLine     = line;
448     }
449 
450   protected:
451     // The front-end ensures that the program is not accessed while linking, so it is safe to
452     // direclty access the state from a potentially parallel job.
453     ProgramD3D *mProgram;
454     ProgramExecutableD3D *mExecutable = nullptr;
455 
456     // Error handling
457     HRESULT mStoredHR = S_OK;
458     std::string mStoredMessage;
459     const char *mStoredFile     = nullptr;
460     const char *mStoredFunction = nullptr;
461     unsigned int mStoredLine    = 0;
462 };
463 
464 class ProgramD3D::LinkTaskD3D final : public LinkLoadTaskD3D
465 {
466   public:
LinkTaskD3D(const gl::Version & clientVersion,const gl::Caps & caps,ProgramD3D * program,gl::ProvokingVertexConvention provokingVertex)467     LinkTaskD3D(const gl::Version &clientVersion,
468                 const gl::Caps &caps,
469                 ProgramD3D *program,
470                 gl::ProvokingVertexConvention provokingVertex)
471         : LinkLoadTaskD3D(program),
472           mClientVersion(clientVersion),
473           mCaps(caps),
474           mProvokingVertex(provokingVertex)
475     {}
476     ~LinkTaskD3D() override = default;
477 
478     void link(const gl::ProgramLinkedResources &resources,
479               const gl::ProgramMergedVaryings &mergedVaryings,
480               std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
481               std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut) override;
482 
483   private:
484     const gl::Version mClientVersion;
485     const gl::Caps &mCaps;
486     const gl::ProvokingVertexConvention mProvokingVertex;
487 };
488 
link(const gl::ProgramLinkedResources & resources,const gl::ProgramMergedVaryings & mergedVaryings,std::vector<std::shared_ptr<LinkSubTask>> * linkSubTasksOut,std::vector<std::shared_ptr<LinkSubTask>> * postLinkSubTasksOut)489 void ProgramD3D::LinkTaskD3D::link(const gl::ProgramLinkedResources &resources,
490                                    const gl::ProgramMergedVaryings &mergedVaryings,
491                                    std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
492                                    std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut)
493 {
494     ANGLE_TRACE_EVENT0("gpu.angle", "LinkTaskD3D::link");
495 
496     ASSERT(linkSubTasksOut && linkSubTasksOut->empty());
497     ASSERT(postLinkSubTasksOut && postLinkSubTasksOut->empty());
498 
499     angle::Result result =
500         mProgram->linkJobImpl(this, mCaps, mClientVersion, resources, mergedVaryings);
501     ASSERT((result == angle::Result::Continue) == (mStoredHR == S_OK));
502 
503     if (result != angle::Result::Continue)
504     {
505         return;
506     }
507 
508     // Create the subtasks
509     if (mExecutable->hasShaderStage(gl::ShaderType::Compute))
510     {
511         linkSubTasksOut->push_back(std::make_shared<GetComputeExecutableTask>(
512             mProgram, mProgram->getAttachedShader(gl::ShaderType::Compute)));
513     }
514     else
515     {
516         // Geometry shaders are currently only used internally, so there is no corresponding shader
517         // object at the interface level. For now the geometry shader debug info is prepended to the
518         // vertex shader.
519         linkSubTasksOut->push_back(std::make_shared<GetVertexExecutableTask>(
520             mProgram, mProgram->getAttachedShader(gl::ShaderType::Vertex)));
521         linkSubTasksOut->push_back(std::make_shared<GetPixelExecutableTask>(
522             mProgram, mProgram->getAttachedShader(gl::ShaderType::Fragment)));
523         linkSubTasksOut->push_back(std::make_shared<GetGeometryExecutableTask>(
524             mProgram, mProgram->getAttachedShader(gl::ShaderType::Vertex), mCaps,
525             mProvokingVertex));
526     }
527 }
528 
529 class ProgramD3D::LoadTaskD3D final : public LinkLoadTaskD3D
530 {
531   public:
LoadTaskD3D(ProgramD3D * program,angle::MemoryBuffer && streamData)532     LoadTaskD3D(ProgramD3D *program, angle::MemoryBuffer &&streamData)
533         : LinkLoadTaskD3D(program), mStreamData(std::move(streamData))
534     {}
535     ~LoadTaskD3D() override = default;
536 
load(std::vector<std::shared_ptr<LinkSubTask>> * linkSubTasksOut,std::vector<std::shared_ptr<LinkSubTask>> * postLinkSubTasksOut)537     void load(std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
538               std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut) override
539     {
540         ANGLE_TRACE_EVENT0("gpu.angle", "LoadTaskD3D::load");
541 
542         ASSERT(linkSubTasksOut && linkSubTasksOut->empty());
543         ASSERT(postLinkSubTasksOut && postLinkSubTasksOut->empty());
544 
545         gl::BinaryInputStream stream(mStreamData.data(), mStreamData.size());
546         mResult = mExecutable->loadBinaryShaderExecutables(this, mProgram->mRenderer, &stream);
547 
548         return;
549     }
550 
getResult(const gl::Context * context,gl::InfoLog & infoLog)551     angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
552     {
553         ANGLE_TRY(LinkLoadTaskD3D::getResult(context, infoLog));
554         return mResult;
555     }
556 
557   private:
558     angle::MemoryBuffer mStreamData;
559     angle::Result mResult = angle::Result::Continue;
560 };
561 
ProgramD3D(const gl::ProgramState & state,RendererD3D * renderer)562 ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer)
563     : ProgramImpl(state), mRenderer(renderer)
564 {}
565 
566 ProgramD3D::~ProgramD3D() = default;
567 
destroy(const gl::Context * context)568 void ProgramD3D::destroy(const gl::Context *context)
569 {
570     getExecutable()->reset();
571 }
572 
load(const gl::Context * context,gl::BinaryInputStream * stream,std::shared_ptr<LinkTask> * loadTaskOut,egl::CacheGetResult * resultOut)573 angle::Result ProgramD3D::load(const gl::Context *context,
574                                gl::BinaryInputStream *stream,
575                                std::shared_ptr<LinkTask> *loadTaskOut,
576                                egl::CacheGetResult *resultOut)
577 {
578     if (!getExecutable()->load(context, mRenderer, stream))
579     {
580         mState.getExecutable().getInfoLog()
581             << "Invalid program binary, device configuration has changed.";
582         return angle::Result::Continue;
583     }
584 
585     // Copy the remaining data from the stream locally so that the client can't modify it when
586     // loading off thread.
587     angle::MemoryBuffer streamData;
588     const size_t dataSize = stream->remainingSize();
589     if (!streamData.resize(dataSize))
590     {
591         mState.getExecutable().getInfoLog()
592             << "Failed to copy program binary data to local buffer.";
593         return angle::Result::Stop;
594     }
595     memcpy(streamData.data(), stream->data() + stream->offset(), dataSize);
596 
597     // Note: pretty much all the above can also be moved to the task
598     *loadTaskOut = std::shared_ptr<LinkTask>(new LoadTaskD3D(this, std::move(streamData)));
599     *resultOut   = egl::CacheGetResult::Success;
600 
601     return angle::Result::Continue;
602 }
603 
save(const gl::Context * context,gl::BinaryOutputStream * stream)604 void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream)
605 {
606     getExecutable()->save(context, mRenderer, stream);
607 }
608 
setBinaryRetrievableHint(bool)609 void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) {}
610 
setSeparable(bool)611 void ProgramD3D::setSeparable(bool /* separable */) {}
612 
prepareForLink(const gl::ShaderMap<ShaderImpl * > & shaders)613 void ProgramD3D::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
614 {
615     ProgramExecutableD3D *executableD3D = getExecutable();
616 
617     for (gl::ShaderType shaderType : gl::AllShaderTypes())
618     {
619         executableD3D->mAttachedShaders[shaderType].reset();
620 
621         if (shaders[shaderType] != nullptr)
622         {
623             const ShaderD3D *shaderD3D                  = GetAs<ShaderD3D>(shaders[shaderType]);
624             executableD3D->mAttachedShaders[shaderType] = shaderD3D->getCompiledState();
625         }
626     }
627 }
628 
link(const gl::Context * context,std::shared_ptr<LinkTask> * linkTaskOut)629 angle::Result ProgramD3D::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
630 {
631     ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::link");
632     const gl::Version &clientVersion = context->getClientVersion();
633     const gl::Caps &caps             = context->getCaps();
634 
635     // Ensure the compiler is initialized to avoid race conditions.
636     ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized(GetImplAs<ContextD3D>(context)));
637 
638     *linkTaskOut = std::shared_ptr<LinkTask>(
639         new LinkTaskD3D(clientVersion, caps, this, context->getState().getProvokingVertex()));
640 
641     return angle::Result::Continue;
642 }
643 
linkJobImpl(d3d::Context * context,const gl::Caps & caps,const gl::Version & clientVersion,const gl::ProgramLinkedResources & resources,const gl::ProgramMergedVaryings & mergedVaryings)644 angle::Result ProgramD3D::linkJobImpl(d3d::Context *context,
645                                       const gl::Caps &caps,
646                                       const gl::Version &clientVersion,
647                                       const gl::ProgramLinkedResources &resources,
648                                       const gl::ProgramMergedVaryings &mergedVaryings)
649 {
650     ProgramExecutableD3D *executableD3D = getExecutable();
651 
652     const gl::SharedCompiledShaderState &computeShader =
653         mState.getAttachedShader(gl::ShaderType::Compute);
654     if (computeShader)
655     {
656         const gl::SharedCompiledShaderState &shader =
657             mState.getAttachedShader(gl::ShaderType::Compute);
658         executableD3D->mShaderHLSL[gl::ShaderType::Compute] = shader->translatedSource;
659 
660         executableD3D->mShaderSamplers[gl::ShaderType::Compute].resize(
661             caps.maxShaderTextureImageUnits[gl::ShaderType::Compute]);
662         executableD3D->mImages[gl::ShaderType::Compute].resize(caps.maxImageUnits);
663         executableD3D->mReadonlyImages[gl::ShaderType::Compute].resize(caps.maxImageUnits);
664 
665         executableD3D->mShaderUniformsDirty.set(gl::ShaderType::Compute);
666 
667         linkResources(resources);
668 
669         for (const sh::ShaderVariable &uniform : computeShader->uniforms)
670         {
671             if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
672             {
673                 executableD3D->mImage2DUniforms[gl::ShaderType::Compute].push_back(uniform);
674             }
675         }
676 
677         executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
678 
679         return angle::Result::Continue;
680     }
681 
682     for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
683     {
684         const gl::SharedCompiledShaderState &shader = mState.getAttachedShader(shaderType);
685         if (shader)
686         {
687             executableD3D->mAttachedShaders[shaderType]->generateWorkarounds(
688                 &executableD3D->mShaderWorkarounds[shaderType]);
689             executableD3D->mShaderSamplers[shaderType].resize(
690                 caps.maxShaderTextureImageUnits[shaderType]);
691             executableD3D->mImages[shaderType].resize(caps.maxImageUnits);
692             executableD3D->mReadonlyImages[shaderType].resize(caps.maxImageUnits);
693 
694             executableD3D->mShaderUniformsDirty.set(shaderType);
695 
696             for (const sh::ShaderVariable &uniform : shader->uniforms)
697             {
698                 if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
699                 {
700                     executableD3D->mImage2DUniforms[shaderType].push_back(uniform);
701                 }
702             }
703 
704             for (const std::string &slowBlock :
705                  executableD3D->mAttachedShaders[shaderType]->slowCompilingUniformBlockSet)
706             {
707                 WARN() << "Uniform block '" << slowBlock << "' will be slow to compile. "
708                        << "See UniformBlockToStructuredBufferTranslation.md "
709                        << "(https://shorturl.at/drFY7) for details.";
710             }
711         }
712     }
713 
714     if (mRenderer->getNativeLimitations().noFrontFacingSupport)
715     {
716         const SharedCompiledShaderStateD3D &fragmentShader =
717             executableD3D->mAttachedShaders[gl::ShaderType::Fragment];
718         if (fragmentShader && fragmentShader->usesFrontFacing)
719         {
720             mState.getExecutable().getInfoLog()
721                 << "The current renderer doesn't support gl_FrontFacing";
722             // Fail compilation
723             ANGLE_CHECK_HR(context, false, "gl_FrontFacing not supported", E_NOTIMPL);
724         }
725     }
726 
727     const gl::VaryingPacking &varyingPacking =
728         resources.varyingPacking.getOutputPacking(gl::ShaderType::Vertex);
729 
730     ProgramD3DMetadata metadata(mRenderer, mState.getAttachedShader(gl::ShaderType::Fragment),
731                                 executableD3D->mAttachedShaders,
732                                 mState.getAttachedShader(gl::ShaderType::Vertex)->shaderVersion);
733     BuiltinVaryingsD3D builtins(metadata, varyingPacking);
734 
735     DynamicHLSL::GenerateShaderLinkHLSL(mRenderer, caps, mState.getAttachedShaders(),
736                                         executableD3D->mAttachedShaders, metadata, varyingPacking,
737                                         builtins, &executableD3D->mShaderHLSL);
738 
739     executableD3D->mUsesPointSize =
740         executableD3D->mAttachedShaders[gl::ShaderType::Vertex] &&
741         executableD3D->mAttachedShaders[gl::ShaderType::Vertex]->usesPointSize;
742     DynamicHLSL::GetPixelShaderOutputKey(mRenderer, caps, clientVersion, mState.getExecutable(),
743                                          metadata, &executableD3D->mPixelShaderKey);
744     executableD3D->mFragDepthUsage      = metadata.getFragDepthUsage();
745     executableD3D->mUsesSampleMask      = metadata.usesSampleMask();
746     executableD3D->mUsesVertexID        = metadata.usesVertexID();
747     executableD3D->mUsesViewID          = metadata.usesViewID();
748     executableD3D->mHasMultiviewEnabled = metadata.hasMultiviewEnabled();
749 
750     // Cache if we use flat shading
751     executableD3D->mUsesFlatInterpolation =
752         FindFlatInterpolationVarying(mState.getAttachedShaders());
753 
754     if (mRenderer->getMajorShaderModel() >= 4)
755     {
756         executableD3D->mGeometryShaderPreamble = DynamicHLSL::GenerateGeometryShaderPreamble(
757             mRenderer, varyingPacking, builtins, executableD3D->mHasMultiviewEnabled,
758             metadata.canSelectViewInVertexShader());
759     }
760 
761     executableD3D->initAttribLocationsToD3DSemantic(
762         mState.getAttachedShader(gl::ShaderType::Vertex));
763 
764     executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
765 
766     executableD3D->gatherTransformFeedbackVaryings(mRenderer, varyingPacking,
767                                                    mState.getTransformFeedbackVaryingNames(),
768                                                    builtins[gl::ShaderType::Vertex]);
769 
770     linkResources(resources);
771 
772     if (mState.getAttachedShader(gl::ShaderType::Vertex))
773     {
774         executableD3D->updateCachedInputLayoutFromShader(
775             mRenderer, mState.getAttachedShader(gl::ShaderType::Vertex));
776     }
777 
778     return angle::Result::Continue;
779 }
780 
validate(const gl::Caps &)781 GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/)
782 {
783     // TODO(jmadill): Do something useful here?
784     return GL_TRUE;
785 }
786 
linkResources(const gl::ProgramLinkedResources & resources)787 void ProgramD3D::linkResources(const gl::ProgramLinkedResources &resources)
788 {
789     HLSLBlockLayoutEncoderFactory hlslEncoderFactory;
790     gl::ProgramLinkedResourcesLinker linker(&hlslEncoderFactory);
791 
792     linker.linkResources(mState, resources);
793 
794     ProgramExecutableD3D *executableD3D = getExecutable();
795 
796     executableD3D->initializeUniformBlocks();
797     executableD3D->initializeShaderStorageBlocks(mState.getAttachedShaders());
798 }
799 
800 }  // namespace rx
801