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