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