• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,EGLenum clientType,int shaderVersion)178 ProgramD3DMetadata::ProgramD3DMetadata(
179     RendererD3D *renderer,
180     const gl::SharedCompiledShaderState &fragmentShader,
181     const gl::ShaderMap<SharedCompiledShaderStateD3D> &attachedShaders,
182     EGLenum clientType,
183     int shaderVersion)
184     : mRendererMajorShaderModel(renderer->getMajorShaderModel()),
185       mShaderModelSuffix(renderer->getShaderModelSuffix()),
186       mUsesInstancedPointSpriteEmulation(
187           renderer->getFeatures().useInstancedPointSpriteEmulation.enabled),
188       mUsesViewScale(renderer->presentPathFastEnabled()),
189       mCanSelectViewInVertexShader(renderer->canSelectViewInVertexShader()),
190       mFragmentShader(fragmentShader),
191       mAttachedShaders(attachedShaders),
192       mClientType(clientType),
193       mShaderVersion(shaderVersion)
194 {}
195 
196 ProgramD3DMetadata::~ProgramD3DMetadata() = default;
197 
getRendererMajorShaderModel() const198 int ProgramD3DMetadata::getRendererMajorShaderModel() const
199 {
200     return mRendererMajorShaderModel;
201 }
202 
usesBroadcast(const gl::Version & clientVersion) const203 bool ProgramD3DMetadata::usesBroadcast(const gl::Version &clientVersion) const
204 {
205     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
206     return shader && shader->usesFragColor && shader->usesMultipleRenderTargets &&
207            clientVersion.major < 3;
208 }
209 
usesSecondaryColor() const210 bool ProgramD3DMetadata::usesSecondaryColor() const
211 {
212     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
213     return shader && shader->usesSecondaryColor;
214 }
215 
getFragDepthUsage() const216 FragDepthUsage ProgramD3DMetadata::getFragDepthUsage() const
217 {
218     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
219     return shader ? shader->fragDepthUsage : FragDepthUsage::Unused;
220 }
221 
usesPointCoord() const222 bool ProgramD3DMetadata::usesPointCoord() const
223 {
224     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
225     return shader && shader->usesPointCoord;
226 }
227 
usesFragCoord() const228 bool ProgramD3DMetadata::usesFragCoord() const
229 {
230     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
231     return shader && shader->usesFragCoord;
232 }
233 
usesPointSize() const234 bool ProgramD3DMetadata::usesPointSize() const
235 {
236     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
237     return shader && shader->usesPointSize;
238 }
239 
usesInsertedPointCoordValue() const240 bool ProgramD3DMetadata::usesInsertedPointCoordValue() const
241 {
242     return (!usesPointSize() || !mUsesInstancedPointSpriteEmulation) && usesPointCoord() &&
243            mRendererMajorShaderModel >= 4;
244 }
245 
usesViewScale() const246 bool ProgramD3DMetadata::usesViewScale() const
247 {
248     return mUsesViewScale;
249 }
250 
hasMultiviewEnabled() const251 bool ProgramD3DMetadata::hasMultiviewEnabled() const
252 {
253     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
254     return shader && shader->hasMultiviewEnabled;
255 }
256 
usesVertexID() const257 bool ProgramD3DMetadata::usesVertexID() const
258 {
259     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
260     return shader && shader->usesVertexID;
261 }
262 
usesViewID() const263 bool ProgramD3DMetadata::usesViewID() const
264 {
265     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
266     return shader && shader->usesViewID;
267 }
268 
canSelectViewInVertexShader() const269 bool ProgramD3DMetadata::canSelectViewInVertexShader() const
270 {
271     return mCanSelectViewInVertexShader;
272 }
273 
addsPointCoordToVertexShader() const274 bool ProgramD3DMetadata::addsPointCoordToVertexShader() const
275 {
276     // PointSprite emulation requiress that gl_PointCoord is present in the vertex shader
277     // VS_OUTPUT structure to ensure compatibility with the generated PS_INPUT of the pixel shader.
278     // Even with a geometry shader, the app can render triangles or lines and reference
279     // gl_PointCoord in the fragment shader, requiring us to provide a placeholder value. For
280     // simplicity, we always add this to the vertex shader when the fragment shader
281     // references gl_PointCoord, even if we could skip it in the geometry shader.
282     return (mUsesInstancedPointSpriteEmulation && usesPointCoord()) ||
283            usesInsertedPointCoordValue();
284 }
285 
usesTransformFeedbackGLPosition() const286 bool ProgramD3DMetadata::usesTransformFeedbackGLPosition() const
287 {
288     // gl_Position only needs to be outputted from the vertex shader if transform feedback is
289     // active. This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from
290     // the vertex shader in this case. This saves us 1 output vector.
291     return !(mRendererMajorShaderModel >= 4 && mShaderModelSuffix != "");
292 }
293 
usesSystemValuePointSize() const294 bool ProgramD3DMetadata::usesSystemValuePointSize() const
295 {
296     return !mUsesInstancedPointSpriteEmulation && usesPointSize();
297 }
298 
usesMultipleFragmentOuts() const299 bool ProgramD3DMetadata::usesMultipleFragmentOuts() const
300 {
301     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
302     return shader && shader->usesMultipleRenderTargets;
303 }
304 
usesCustomOutVars() const305 bool ProgramD3DMetadata::usesCustomOutVars() const
306 {
307     switch (mClientType)
308     {
309         case EGL_OPENGL_API:
310             return mShaderVersion >= 130;
311         default:
312             return mShaderVersion >= 300;
313     }
314 }
315 
usesSampleMask() const316 bool ProgramD3DMetadata::usesSampleMask() const
317 {
318     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Fragment];
319     return shader && shader->usesSampleMask;
320 }
321 
getFragmentShader() const322 const gl::SharedCompiledShaderState &ProgramD3DMetadata::getFragmentShader() const
323 {
324     return mFragmentShader;
325 }
326 
getClipDistanceArraySize() const327 uint8_t ProgramD3DMetadata::getClipDistanceArraySize() const
328 {
329     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
330     return shader ? shader->clipDistanceSize : 0;
331 }
332 
getCullDistanceArraySize() const333 uint8_t ProgramD3DMetadata::getCullDistanceArraySize() const
334 {
335     const SharedCompiledShaderStateD3D &shader = mAttachedShaders[gl::ShaderType::Vertex];
336     return shader ? shader->cullDistanceSize : 0;
337 }
338 
339 // ProgramD3D Implementation
340 
341 class ProgramD3D::GetVertexExecutableTask : public GetExecutableTask
342 {
343   public:
GetVertexExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)344     GetVertexExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
345         : GetExecutableTask(program, shader)
346     {}
347     ~GetVertexExecutableTask() override = default;
348 
operator ()()349     void operator()() override
350     {
351         ANGLE_TRACE_EVENT0("gpu.angle", "GetVertexExecutableTask::run");
352 
353         mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Vertex);
354         mResult = mExecutable->getVertexExecutableForCachedInputLayout(
355             this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
356     }
357 };
358 
359 class ProgramD3D::GetPixelExecutableTask : public GetExecutableTask
360 {
361   public:
GetPixelExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)362     GetPixelExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
363         : GetExecutableTask(program, shader)
364     {}
365     ~GetPixelExecutableTask() override = default;
366 
operator ()()367     void operator()() override
368     {
369         ANGLE_TRACE_EVENT0("gpu.angle", "GetPixelExecutableTask::run");
370         if (!mShader)
371         {
372             return;
373         }
374 
375         mExecutable->updateCachedOutputLayoutFromShader();
376         mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Fragment);
377         mResult = mExecutable->getPixelExecutableForCachedOutputLayout(
378             this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
379     }
380 };
381 
382 class ProgramD3D::GetGeometryExecutableTask : public GetExecutableTask
383 {
384   public:
GetGeometryExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader,const gl::Caps & caps,gl::ProvokingVertexConvention provokingVertex)385     GetGeometryExecutableTask(ProgramD3D *program,
386                               const SharedCompiledShaderStateD3D &shader,
387                               const gl::Caps &caps,
388                               gl::ProvokingVertexConvention provokingVertex)
389         : GetExecutableTask(program, shader), mCaps(caps), mProvokingVertex(provokingVertex)
390     {}
391     ~GetGeometryExecutableTask() override = default;
392 
operator ()()393     void operator()() override
394     {
395         ANGLE_TRACE_EVENT0("gpu.angle", "GetGeometryExecutableTask::run");
396         // Auto-generate the geometry shader here, if we expect to be using point rendering in
397         // D3D11.
398         if (mExecutable->usesGeometryShader(mProgram->mRenderer, mProvokingVertex,
399                                             gl::PrimitiveMode::Points))
400         {
401             mResult = mExecutable->getGeometryExecutableForPrimitiveType(
402                 this, mProgram->mRenderer, mCaps, mProvokingVertex, gl::PrimitiveMode::Points,
403                 &mShaderExecutable, &mInfoLog);
404         }
405     }
406 
407   private:
408     const gl::Caps &mCaps;
409     gl::ProvokingVertexConvention mProvokingVertex;
410 };
411 
412 class ProgramD3D::GetComputeExecutableTask : public GetExecutableTask
413 {
414   public:
GetComputeExecutableTask(ProgramD3D * program,const SharedCompiledShaderStateD3D & shader)415     GetComputeExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
416         : GetExecutableTask(program, shader)
417     {}
418     ~GetComputeExecutableTask() override = default;
419 
operator ()()420     void operator()() override
421     {
422         ANGLE_TRACE_EVENT0("gpu.angle", "GetComputeExecutableTask::run");
423 
424         mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Compute);
425         mResult = mExecutable->getComputeExecutableForImage2DBindLayout(
426             this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
427     }
428 };
429 
430 class ProgramD3D::LinkLoadTaskD3D : public d3d::Context, public LinkTask
431 {
432   public:
LinkLoadTaskD3D(ProgramD3D * program)433     LinkLoadTaskD3D(ProgramD3D *program) : mProgram(program), mExecutable(program->getExecutable())
434     {
435         ASSERT(mProgram);
436     }
437     ~LinkLoadTaskD3D() override = default;
438 
getResult(const gl::Context * context,gl::InfoLog & infoLog)439     angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
440     {
441         if (mStoredHR != S_OK)
442         {
443             GetImplAs<ContextD3D>(context)->handleResult(mStoredHR, mStoredMessage.c_str(),
444                                                          mStoredFile, mStoredFunction, mStoredLine);
445             return angle::Result::Stop;
446         }
447 
448         return angle::Result::Continue;
449     }
450 
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)451     void handleResult(HRESULT hr,
452                       const char *message,
453                       const char *file,
454                       const char *function,
455                       unsigned int line) override
456     {
457         mStoredHR       = hr;
458         mStoredMessage  = message;
459         mStoredFile     = file;
460         mStoredFunction = function;
461         mStoredLine     = line;
462     }
463 
464   protected:
465     // The front-end ensures that the program is not accessed while linking, so it is safe to
466     // direclty access the state from a potentially parallel job.
467     ProgramD3D *mProgram;
468     ProgramExecutableD3D *mExecutable = nullptr;
469 
470     // Error handling
471     HRESULT mStoredHR = S_OK;
472     std::string mStoredMessage;
473     const char *mStoredFile     = nullptr;
474     const char *mStoredFunction = nullptr;
475     unsigned int mStoredLine    = 0;
476 };
477 
478 class ProgramD3D::LinkTaskD3D final : public LinkLoadTaskD3D
479 {
480   public:
LinkTaskD3D(const gl::Version & clientVersion,const gl::Caps & caps,EGLenum clientType,ProgramD3D * program,gl::ProvokingVertexConvention provokingVertex)481     LinkTaskD3D(const gl::Version &clientVersion,
482                 const gl::Caps &caps,
483                 EGLenum clientType,
484                 ProgramD3D *program,
485                 gl::ProvokingVertexConvention provokingVertex)
486         : LinkLoadTaskD3D(program),
487           mClientVersion(clientVersion),
488           mCaps(caps),
489           mClientType(clientType),
490           mProvokingVertex(provokingVertex)
491     {}
492     ~LinkTaskD3D() override = default;
493 
494     void link(const gl::ProgramLinkedResources &resources,
495               const gl::ProgramMergedVaryings &mergedVaryings,
496               std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
497               std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut) override;
498 
499   private:
500     const gl::Version mClientVersion;
501     const gl::Caps &mCaps;
502     const EGLenum mClientType;
503     const gl::ProvokingVertexConvention mProvokingVertex;
504 };
505 
link(const gl::ProgramLinkedResources & resources,const gl::ProgramMergedVaryings & mergedVaryings,std::vector<std::shared_ptr<LinkSubTask>> * linkSubTasksOut,std::vector<std::shared_ptr<LinkSubTask>> * postLinkSubTasksOut)506 void ProgramD3D::LinkTaskD3D::link(const gl::ProgramLinkedResources &resources,
507                                    const gl::ProgramMergedVaryings &mergedVaryings,
508                                    std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
509                                    std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut)
510 {
511     ANGLE_TRACE_EVENT0("gpu.angle", "LinkTaskD3D::link");
512 
513     ASSERT(linkSubTasksOut && linkSubTasksOut->empty());
514     ASSERT(postLinkSubTasksOut && postLinkSubTasksOut->empty());
515 
516     angle::Result result =
517         mProgram->linkJobImpl(this, mCaps, mClientVersion, mClientType, resources, mergedVaryings);
518     ASSERT((result == angle::Result::Continue) == (mStoredHR == S_OK));
519 
520     if (result != angle::Result::Continue)
521     {
522         return;
523     }
524 
525     // Create the subtasks
526     if (mExecutable->hasShaderStage(gl::ShaderType::Compute))
527     {
528         linkSubTasksOut->push_back(std::make_shared<GetComputeExecutableTask>(
529             mProgram, mProgram->getAttachedShader(gl::ShaderType::Compute)));
530     }
531     else
532     {
533         // Geometry shaders are currently only used internally, so there is no corresponding shader
534         // object at the interface level. For now the geometry shader debug info is prepended to the
535         // vertex shader.
536         linkSubTasksOut->push_back(std::make_shared<GetVertexExecutableTask>(
537             mProgram, mProgram->getAttachedShader(gl::ShaderType::Vertex)));
538         linkSubTasksOut->push_back(std::make_shared<GetPixelExecutableTask>(
539             mProgram, mProgram->getAttachedShader(gl::ShaderType::Fragment)));
540         linkSubTasksOut->push_back(std::make_shared<GetGeometryExecutableTask>(
541             mProgram, mProgram->getAttachedShader(gl::ShaderType::Vertex), mCaps,
542             mProvokingVertex));
543     }
544 }
545 
546 class ProgramD3D::LoadTaskD3D final : public LinkLoadTaskD3D
547 {
548   public:
LoadTaskD3D(ProgramD3D * program,angle::MemoryBuffer && streamData)549     LoadTaskD3D(ProgramD3D *program, angle::MemoryBuffer &&streamData)
550         : LinkLoadTaskD3D(program), mStreamData(std::move(streamData))
551     {}
552     ~LoadTaskD3D() override = default;
553 
load(std::vector<std::shared_ptr<LinkSubTask>> * linkSubTasksOut,std::vector<std::shared_ptr<LinkSubTask>> * postLinkSubTasksOut)554     void load(std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
555               std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut) override
556     {
557         ANGLE_TRACE_EVENT0("gpu.angle", "LoadTaskD3D::load");
558 
559         ASSERT(linkSubTasksOut && linkSubTasksOut->empty());
560         ASSERT(postLinkSubTasksOut && postLinkSubTasksOut->empty());
561 
562         gl::BinaryInputStream stream(mStreamData.data(), mStreamData.size());
563         mResult = mExecutable->loadBinaryShaderExecutables(this, mProgram->mRenderer, &stream);
564 
565         return;
566     }
567 
getResult(const gl::Context * context,gl::InfoLog & infoLog)568     angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
569     {
570         ANGLE_TRY(LinkLoadTaskD3D::getResult(context, infoLog));
571         return mResult;
572     }
573 
574   private:
575     angle::MemoryBuffer mStreamData;
576     angle::Result mResult = angle::Result::Continue;
577 };
578 
ProgramD3D(const gl::ProgramState & state,RendererD3D * renderer)579 ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer)
580     : ProgramImpl(state), mRenderer(renderer)
581 {}
582 
583 ProgramD3D::~ProgramD3D() = default;
584 
destroy(const gl::Context * context)585 void ProgramD3D::destroy(const gl::Context *context)
586 {
587     getExecutable()->reset();
588 }
589 
load(const gl::Context * context,gl::BinaryInputStream * stream,std::shared_ptr<LinkTask> * loadTaskOut,egl::CacheGetResult * resultOut)590 angle::Result ProgramD3D::load(const gl::Context *context,
591                                gl::BinaryInputStream *stream,
592                                std::shared_ptr<LinkTask> *loadTaskOut,
593                                egl::CacheGetResult *resultOut)
594 {
595     if (!getExecutable()->load(context, mRenderer, stream))
596     {
597         mState.getExecutable().getInfoLog()
598             << "Invalid program binary, device configuration has changed.";
599         return angle::Result::Continue;
600     }
601 
602     // Copy the remaining data from the stream locally so that the client can't modify it when
603     // loading off thread.
604     angle::MemoryBuffer streamData;
605     const size_t dataSize = stream->remainingSize();
606     if (!streamData.resize(dataSize))
607     {
608         mState.getExecutable().getInfoLog()
609             << "Failed to copy program binary data to local buffer.";
610         return angle::Result::Stop;
611     }
612     memcpy(streamData.data(), stream->data() + stream->offset(), dataSize);
613 
614     // Note: pretty much all the above can also be moved to the task
615     *loadTaskOut = std::shared_ptr<LinkTask>(new LoadTaskD3D(this, std::move(streamData)));
616     *resultOut   = egl::CacheGetResult::Success;
617 
618     return angle::Result::Continue;
619 }
620 
save(const gl::Context * context,gl::BinaryOutputStream * stream)621 void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream)
622 {
623     getExecutable()->save(context, mRenderer, stream);
624 }
625 
setBinaryRetrievableHint(bool)626 void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) {}
627 
setSeparable(bool)628 void ProgramD3D::setSeparable(bool /* separable */) {}
629 
prepareForLink(const gl::ShaderMap<ShaderImpl * > & shaders)630 void ProgramD3D::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
631 {
632     ProgramExecutableD3D *executableD3D = getExecutable();
633 
634     for (gl::ShaderType shaderType : gl::AllShaderTypes())
635     {
636         executableD3D->mAttachedShaders[shaderType].reset();
637 
638         if (shaders[shaderType] != nullptr)
639         {
640             const ShaderD3D *shaderD3D                  = GetAs<ShaderD3D>(shaders[shaderType]);
641             executableD3D->mAttachedShaders[shaderType] = shaderD3D->getCompiledState();
642         }
643     }
644 }
645 
link(const gl::Context * context,std::shared_ptr<LinkTask> * linkTaskOut)646 angle::Result ProgramD3D::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
647 {
648     ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::link");
649     const gl::Version &clientVersion = context->getClientVersion();
650     const gl::Caps &caps             = context->getCaps();
651     EGLenum clientType               = context->getClientType();
652 
653     // Ensure the compiler is initialized to avoid race conditions.
654     ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized(GetImplAs<ContextD3D>(context)));
655 
656     *linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskD3D(
657         clientVersion, caps, clientType, this, context->getState().getProvokingVertex()));
658 
659     return angle::Result::Continue;
660 }
661 
linkJobImpl(d3d::Context * context,const gl::Caps & caps,const gl::Version & clientVersion,EGLenum clientType,const gl::ProgramLinkedResources & resources,const gl::ProgramMergedVaryings & mergedVaryings)662 angle::Result ProgramD3D::linkJobImpl(d3d::Context *context,
663                                       const gl::Caps &caps,
664                                       const gl::Version &clientVersion,
665                                       EGLenum clientType,
666                                       const gl::ProgramLinkedResources &resources,
667                                       const gl::ProgramMergedVaryings &mergedVaryings)
668 {
669     ProgramExecutableD3D *executableD3D = getExecutable();
670 
671     const gl::SharedCompiledShaderState &computeShader =
672         mState.getAttachedShader(gl::ShaderType::Compute);
673     if (computeShader)
674     {
675         const gl::SharedCompiledShaderState &shader =
676             mState.getAttachedShader(gl::ShaderType::Compute);
677         executableD3D->mShaderHLSL[gl::ShaderType::Compute] = shader->translatedSource;
678 
679         executableD3D->mShaderSamplers[gl::ShaderType::Compute].resize(
680             caps.maxShaderTextureImageUnits[gl::ShaderType::Compute]);
681         executableD3D->mImages[gl::ShaderType::Compute].resize(caps.maxImageUnits);
682         executableD3D->mReadonlyImages[gl::ShaderType::Compute].resize(caps.maxImageUnits);
683 
684         executableD3D->mShaderUniformsDirty.set(gl::ShaderType::Compute);
685 
686         linkResources(resources);
687 
688         for (const sh::ShaderVariable &uniform : computeShader->uniforms)
689         {
690             if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
691             {
692                 executableD3D->mImage2DUniforms[gl::ShaderType::Compute].push_back(uniform);
693             }
694         }
695 
696         executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
697 
698         return angle::Result::Continue;
699     }
700 
701     for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
702     {
703         const gl::SharedCompiledShaderState &shader = mState.getAttachedShader(shaderType);
704         if (shader)
705         {
706             executableD3D->mAttachedShaders[shaderType]->generateWorkarounds(
707                 &executableD3D->mShaderWorkarounds[shaderType]);
708             executableD3D->mShaderSamplers[shaderType].resize(
709                 caps.maxShaderTextureImageUnits[shaderType]);
710             executableD3D->mImages[shaderType].resize(caps.maxImageUnits);
711             executableD3D->mReadonlyImages[shaderType].resize(caps.maxImageUnits);
712 
713             executableD3D->mShaderUniformsDirty.set(shaderType);
714 
715             for (const sh::ShaderVariable &uniform : shader->uniforms)
716             {
717                 if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
718                 {
719                     executableD3D->mImage2DUniforms[shaderType].push_back(uniform);
720                 }
721             }
722 
723             for (const std::string &slowBlock :
724                  executableD3D->mAttachedShaders[shaderType]->slowCompilingUniformBlockSet)
725             {
726                 WARN() << "Uniform block '" << slowBlock << "' will be slow to compile. "
727                        << "See UniformBlockToStructuredBufferTranslation.md "
728                        << "(https://shorturl.at/drFY7) for details.";
729             }
730         }
731     }
732 
733     if (mRenderer->getNativeLimitations().noFrontFacingSupport)
734     {
735         const SharedCompiledShaderStateD3D &fragmentShader =
736             executableD3D->mAttachedShaders[gl::ShaderType::Fragment];
737         if (fragmentShader && fragmentShader->usesFrontFacing)
738         {
739             mState.getExecutable().getInfoLog()
740                 << "The current renderer doesn't support gl_FrontFacing";
741             // Fail compilation
742             ANGLE_CHECK_HR(context, false, "gl_FrontFacing not supported", E_NOTIMPL);
743         }
744     }
745 
746     const gl::VaryingPacking &varyingPacking =
747         resources.varyingPacking.getOutputPacking(gl::ShaderType::Vertex);
748 
749     ProgramD3DMetadata metadata(mRenderer, mState.getAttachedShader(gl::ShaderType::Fragment),
750                                 executableD3D->mAttachedShaders, clientType,
751                                 mState.getAttachedShader(gl::ShaderType::Vertex)->shaderVersion);
752     BuiltinVaryingsD3D builtins(metadata, varyingPacking);
753 
754     DynamicHLSL::GenerateShaderLinkHLSL(mRenderer, caps, mState.getAttachedShaders(),
755                                         executableD3D->mAttachedShaders, metadata, varyingPacking,
756                                         builtins, &executableD3D->mShaderHLSL);
757 
758     executableD3D->mUsesPointSize =
759         executableD3D->mAttachedShaders[gl::ShaderType::Vertex] &&
760         executableD3D->mAttachedShaders[gl::ShaderType::Vertex]->usesPointSize;
761     DynamicHLSL::GetPixelShaderOutputKey(mRenderer, caps, clientVersion, mState.getExecutable(),
762                                          metadata, &executableD3D->mPixelShaderKey);
763     executableD3D->mFragDepthUsage      = metadata.getFragDepthUsage();
764     executableD3D->mUsesSampleMask      = metadata.usesSampleMask();
765     executableD3D->mUsesVertexID        = metadata.usesVertexID();
766     executableD3D->mUsesViewID          = metadata.usesViewID();
767     executableD3D->mHasMultiviewEnabled = metadata.hasMultiviewEnabled();
768 
769     // Cache if we use flat shading
770     executableD3D->mUsesFlatInterpolation =
771         FindFlatInterpolationVarying(mState.getAttachedShaders());
772 
773     if (mRenderer->getMajorShaderModel() >= 4)
774     {
775         executableD3D->mGeometryShaderPreamble = DynamicHLSL::GenerateGeometryShaderPreamble(
776             mRenderer, varyingPacking, builtins, executableD3D->mHasMultiviewEnabled,
777             metadata.canSelectViewInVertexShader());
778     }
779 
780     executableD3D->initAttribLocationsToD3DSemantic(
781         mState.getAttachedShader(gl::ShaderType::Vertex));
782 
783     executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
784 
785     executableD3D->gatherTransformFeedbackVaryings(mRenderer, varyingPacking,
786                                                    mState.getTransformFeedbackVaryingNames(),
787                                                    builtins[gl::ShaderType::Vertex]);
788 
789     linkResources(resources);
790 
791     if (mState.getAttachedShader(gl::ShaderType::Vertex))
792     {
793         executableD3D->updateCachedInputLayoutFromShader(
794             mRenderer, mState.getAttachedShader(gl::ShaderType::Vertex));
795     }
796 
797     return angle::Result::Continue;
798 }
799 
validate(const gl::Caps &)800 GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/)
801 {
802     // TODO(jmadill): Do something useful here?
803     return GL_TRUE;
804 }
805 
linkResources(const gl::ProgramLinkedResources & resources)806 void ProgramD3D::linkResources(const gl::ProgramLinkedResources &resources)
807 {
808     HLSLBlockLayoutEncoderFactory hlslEncoderFactory;
809     gl::ProgramLinkedResourcesLinker linker(&hlslEncoderFactory);
810 
811     linker.linkResources(mState, resources);
812 
813     ProgramExecutableD3D *executableD3D = getExecutable();
814 
815     executableD3D->initializeUniformBlocks();
816     executableD3D->initializeShaderStorageBlocks(mState.getAttachedShaders());
817 }
818 
819 }  // namespace rx
820