Bug 1497677 - Revendor ANGLE with parallel link and provoking_vertex_dont_care for WR.
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 09 Oct 2018 14:02:32 -0700
changeset 496102 c19f84cb5fcbf896171350432d4476ba27d11d15
parent 496101 296fa4a869ae27297569005bb09b5bc4f3750ca0
child 496103 60699c2387f6e51398c345996a97551a867bd2d7
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1497677
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1497677 - Revendor ANGLE with parallel link and provoking_vertex_dont_care for WR.
gfx/angle/checkout/include/EGL/eglext_angle.h
gfx/angle/checkout/out/gen/angle/id/commit.h
gfx/angle/checkout/src/libANGLE/Caps.cpp
gfx/angle/checkout/src/libANGLE/Caps.h
gfx/angle/checkout/src/libANGLE/Context.cpp
gfx/angle/checkout/src/libANGLE/Context.h
gfx/angle/checkout/src/libANGLE/Display.cpp
gfx/angle/checkout/src/libANGLE/MemoryProgramCache.cpp
gfx/angle/checkout/src/libANGLE/MemoryProgramCache.h
gfx/angle/checkout/src/libANGLE/Program.cpp
gfx/angle/checkout/src/libANGLE/renderer/ProgramImpl.h
gfx/angle/checkout/src/libANGLE/renderer/d3d/ProgramD3D.cpp
gfx/angle/checkout/src/libANGLE/renderer/d3d/ProgramD3D.h
gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
gfx/angle/checkout/src/libANGLE/validationEGL.cpp
gfx/angle/cherry_picks.txt
--- a/gfx/angle/checkout/include/EGL/eglext_angle.h
+++ b/gfx/angle/checkout/include/EGL/eglext_angle.h
@@ -181,11 +181,16 @@ EGLAPI EGLint EGLAPIENTRY eglProgramCach
 #define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
 #endif /* EGL_ANGLE_iosurface_client_buffer */
 
 #ifndef EGL_ANGLE_create_context_extensions_enabled
 #define EGL_ANGLE_create_context_extensions_enabled 1
 #define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
 #endif /* EGL_ANGLE_create_context_extensions_enabled */
 
+#ifndef EGL_MOZ_create_context_provoking_vertex_dont_care
+#define EGL_MOZ_create_context_provoking_vertex_dont_care 1
+#define EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
+#endif /* EGL_MOZ_create_context_provoking_vertex_dont_care */
+
 // clang-format on
 
 #endif  // INCLUDE_EGL_EGLEXT_ANGLE_
--- a/gfx/angle/checkout/out/gen/angle/id/commit.h
+++ b/gfx/angle/checkout/out/gen/angle/id/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "4fb8d7f978ad"
+#define ANGLE_COMMIT_HASH "598f2502e3a4"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2018-09-28 14:28:35 -0700"
+#define ANGLE_COMMIT_DATE "2018-10-09 13:54:05 -0700"
--- a/gfx/angle/checkout/src/libANGLE/Caps.cpp
+++ b/gfx/angle/checkout/src/libANGLE/Caps.cpp
@@ -1313,16 +1313,17 @@ DisplayExtensions::DisplayExtensions()
       pixelFormatFloat(false),
       surfacelessContext(false),
       displayTextureShareGroup(false),
       createContextClientArrays(false),
       programCacheControl(false),
       robustResourceInitialization(false),
       iosurfaceClientBuffer(false),
       createContextExtensionsEnabled(false),
+      provokingVertexDontCare(false),
       presentationTime(false)
 {
 }
 
 std::vector<std::string> DisplayExtensions::getStrings() const
 {
     std::vector<std::string> extensionStrings;
 
@@ -1360,16 +1361,17 @@ std::vector<std::string> DisplayExtensio
     InsertExtensionString("EGL_EXT_pixel_format_float",                          pixelFormatFloat,                   &extensionStrings);
     InsertExtensionString("EGL_KHR_surfaceless_context",                         surfacelessContext,                 &extensionStrings);
     InsertExtensionString("EGL_ANGLE_display_texture_share_group",               displayTextureShareGroup,           &extensionStrings);
     InsertExtensionString("EGL_ANGLE_create_context_client_arrays",              createContextClientArrays,          &extensionStrings);
     InsertExtensionString("EGL_ANGLE_program_cache_control",                     programCacheControl,                &extensionStrings);
     InsertExtensionString("EGL_ANGLE_robust_resource_initialization",            robustResourceInitialization,       &extensionStrings);
     InsertExtensionString("EGL_ANGLE_iosurface_client_buffer",                   iosurfaceClientBuffer,              &extensionStrings);
     InsertExtensionString("EGL_ANGLE_create_context_extensions_enabled",         createContextExtensionsEnabled,     &extensionStrings);
+    InsertExtensionString("EGL_MOZ_create_context_provoking_vertex_dont_care",   provokingVertexDontCare,            &extensionStrings);
     InsertExtensionString("EGL_ANDROID_presentation_time",                       presentationTime,                   &extensionStrings);
     // TODO(jmadill): Enable this when complete.
     //InsertExtensionString("KHR_create_context_no_error",                       createContextNoError,               &extensionStrings);
     // clang-format on
 
     return extensionStrings;
 }
 
--- a/gfx/angle/checkout/src/libANGLE/Caps.h
+++ b/gfx/angle/checkout/src/libANGLE/Caps.h
@@ -771,17 +771,20 @@ struct DisplayExtensions
     bool robustResourceInitialization;
 
     // EGL_ANGLE_iosurface_client_buffer
     bool iosurfaceClientBuffer;
 
     // EGL_ANGLE_create_context_extensions_enabled
     bool createContextExtensionsEnabled;
 
-    // EGL_ANDROID_presentation_time
+    // EGL_MOZ_create_context_provoking_vertex_dont_care
+    bool provokingVertexDontCare;
+
+  // EGL_ANDROID_presentation_time
     bool presentationTime;
 };
 
 struct DeviceExtensions
 {
     DeviceExtensions();
 
     // Generate a vector of supported extension strings
--- a/gfx/angle/checkout/src/libANGLE/Context.cpp
+++ b/gfx/angle/checkout/src/libANGLE/Context.cpp
@@ -213,16 +213,21 @@ bool GetBindGeneratesResource(const egl:
     return (attribs.get(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE) == EGL_TRUE);
 }
 
 bool GetClientArraysEnabled(const egl::AttributeMap &attribs)
 {
     return (attribs.get(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE) == EGL_TRUE);
 }
 
+bool GetProvokingVertexDontCare(const egl::AttributeMap &attribs)
+{
+    return (attribs.get(EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ, EGL_FALSE) == EGL_TRUE);
+}
+
 bool GetRobustResourceInit(const egl::AttributeMap &attribs)
 {
     return (attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE);
 }
 
 std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label)
 {
     std::string labelName;
@@ -353,16 +358,17 @@ Context::Context(rx::EGLImplFactory *imp
       mResetStrategy(GetResetStrategy(attribs)),
       mRobustAccess(GetRobustAccess(attribs)),
       mSurfacelessSupported(displayExtensions.surfacelessContext),
       mExplicitContextAvailable(clientExtensions.explicitContext),
       mCurrentSurface(static_cast<egl::Surface *>(EGL_NO_SURFACE)),
       mCurrentDisplay(static_cast<egl::Display *>(EGL_NO_DISPLAY)),
       mWebGLContext(GetWebGLContext(attribs)),
       mExtensionsEnabled(GetExtensionsEnabled(attribs, mWebGLContext)),
+      mProvokingVertexDontCare(GetProvokingVertexDontCare(attribs)),
       mMemoryProgramCache(memoryProgramCache),
       mVertexArrayObserverBinding(this, kVertexArraySubjectIndex),
       mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex),
       mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex),
       mScratchBuffer(1000u),
       mZeroFilledBuffer(1000u),
       mThreadPool(nullptr)
 {
--- a/gfx/angle/checkout/src/libANGLE/Context.h
+++ b/gfx/angle/checkout/src/libANGLE/Context.h
@@ -1558,16 +1558,19 @@ class Context final : public egl::Labele
     std::shared_ptr<angle::WorkerThreadPool> getWorkerThreadPool() const { return mThreadPool; }
 
     const StateCache &getStateCache() const { return mStateCache; }
 
     void onSubjectStateChange(const Context *context,
                               angle::SubjectIndex index,
                               angle::SubjectMessage message) override;
 
+    // Do we care about the order of the provoking vertex?
+    bool provokingVertexDontCare() const { return mProvokingVertexDontCare; }
+
   private:
     void initialize();
 
     bool noopDraw(PrimitiveMode mode, GLsizei count);
     bool noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei instanceCount);
 
     Error prepareForDraw(PrimitiveMode mode);
     Error prepareForClear(GLbitfield mask);
@@ -1677,16 +1680,17 @@ class Context final : public egl::Labele
     GLenum mResetStrategy;
     const bool mRobustAccess;
     const bool mSurfacelessSupported;
     const bool mExplicitContextAvailable;
     egl::Surface *mCurrentSurface;
     egl::Display *mCurrentDisplay;
     const bool mWebGLContext;
     const bool mExtensionsEnabled;
+    const bool mProvokingVertexDontCare;
     MemoryProgramCache *mMemoryProgramCache;
 
     State::DirtyObjects mDrawDirtyObjects;
     State::DirtyObjects mPathOperationDirtyObjects;
 
     StateCache mStateCache;
 
     State::DirtyBits mTexImageDirtyBits;
--- a/gfx/angle/checkout/src/libANGLE/Display.cpp
+++ b/gfx/angle/checkout/src/libANGLE/Display.cpp
@@ -1087,16 +1087,19 @@ void Display::initDisplayExtensions()
     mDisplayExtensions.getAllProcAddresses = true;
 
     // Enable program cache control since it is not back-end dependent.
     mDisplayExtensions.programCacheControl = true;
 
     // Request extension is implemented in the ANGLE frontend
     mDisplayExtensions.createContextExtensionsEnabled = true;
 
+    // Enable provoking vertex order don't care since it is not back-end dependent.
+    mDisplayExtensions.provokingVertexDontCare = true;
+
     mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
 }
 
 bool Display::isValidNativeWindow(EGLNativeWindowType window) const
 {
     return mImplementation->isValidNativeWindow(window);
 }
 
--- a/gfx/angle/checkout/src/libANGLE/MemoryProgramCache.cpp
+++ b/gfx/angle/checkout/src/libANGLE/MemoryProgramCache.cpp
@@ -203,41 +203,41 @@ MemoryProgramCache::MemoryProgramCache(s
 {
 }
 
 MemoryProgramCache::~MemoryProgramCache()
 {
 }
 
 // static
-LinkResult MemoryProgramCache::Deserialize(const Context *context,
+std::unique_ptr<rx::LinkEvent> MemoryProgramCache::Deserialize(const Context *context,
                                            const Program *program,
                                            ProgramState *state,
                                            const uint8_t *binary,
                                            size_t length,
                                            InfoLog &infoLog)
 {
     BinaryInputStream stream(binary, length);
 
     unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
     stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
     if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
         0)
     {
         infoLog << "Invalid program binary version.";
-        return false;
+        return std::make_unique<rx::LinkEventDone>(false);
     }
 
     int majorVersion = stream.readInt<int>();
     int minorVersion = stream.readInt<int>();
     if (majorVersion != context->getClientMajorVersion() ||
         minorVersion != context->getClientMinorVersion())
     {
         infoLog << "Cannot load program binaries across different ES context versions.";
-        return false;
+        return std::make_unique<rx::LinkEventDone>(false);
     }
 
     state->mComputeShaderLocalSize[0] = stream.readInt<int>();
     state->mComputeShaderLocalSize[1] = stream.readInt<int>();
     state->mComputeShaderLocalSize[2] = stream.readInt<int>();
 
     state->mGeometryShaderInputPrimitiveType  = stream.readEnum<PrimitiveMode>();
     state->mGeometryShaderOutputPrimitiveType = stream.readEnum<PrimitiveMode>();
@@ -339,17 +339,17 @@ LinkResult MemoryProgramCache::Deseriali
 
     unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
 
     // Reject programs that use transform feedback varyings if the hardware cannot support them.
     if (transformFeedbackVaryingCount > 0 &&
         context->getWorkarounds().disableProgramCachingForTransformFeedback)
     {
         infoLog << "Current driver does not support transform feedback in binary programs.";
-        return false;
+        return std::make_unique<rx::LinkEventDone>(false);
     }
 
     ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
     for (unsigned int transformFeedbackVaryingIndex = 0;
          transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
          ++transformFeedbackVaryingIndex)
     {
         sh::Varying varying;
@@ -654,20 +654,19 @@ LinkResult MemoryProgramCache::getProgra
                                           ProgramHash *hashOut)
 {
     ComputeHash(context, program, hashOut);
     const angle::MemoryBuffer *binaryProgram = nullptr;
     LinkResult result(false);
     if (get(*hashOut, &binaryProgram))
     {
         InfoLog infoLog;
-        ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(),
-                                     binaryProgram->size(), infoLog),
-                         result);
-        ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult());
+        auto event = Deserialize(context, program, state, binaryProgram->data(),
+                                 binaryProgram->size(), infoLog);
+        result = event->wait();
         if (!result.getResult())
         {
             // Cache load failed, evict.
             if (mIssuedWarnings++ < kWarningLimit)
             {
                 WARN() << "Failed to load binary from cache: " << infoLog.str();
 
                 if (mIssuedWarnings == kWarningLimit)
--- a/gfx/angle/checkout/src/libANGLE/MemoryProgramCache.h
+++ b/gfx/angle/checkout/src/libANGLE/MemoryProgramCache.h
@@ -10,16 +10,17 @@
 #ifndef LIBANGLE_MEMORY_PROGRAM_CACHE_H_
 #define LIBANGLE_MEMORY_PROGRAM_CACHE_H_
 
 #include <array>
 
 #include "common/MemoryBuffer.h"
 #include "libANGLE/Error.h"
 #include "libANGLE/SizedMRUCache.h"
+#include "libANGLE/renderer/ProgramImpl.h"
 
 namespace gl
 {
 // 160-bit SHA-1 hash key.
 constexpr size_t kProgramHashLength = 20;
 using ProgramHash                   = std::array<uint8_t, kProgramHashLength>;
 }  // namespace gl
 
@@ -56,22 +57,22 @@ class MemoryProgramCache final : angle::
     ~MemoryProgramCache();
 
     // Writes a program's binary to the output memory buffer.
     static void Serialize(const Context *context,
                           const Program *program,
                           angle::MemoryBuffer *binaryOut);
 
     // Loads program state according to the specified binary blob.
-    static LinkResult Deserialize(const Context *context,
-                                  const Program *program,
-                                  ProgramState *state,
-                                  const uint8_t *binary,
-                                  size_t length,
-                                  InfoLog &infoLog);
+    static std::unique_ptr<rx::LinkEvent> Deserialize(const Context *context,
+                                                      const Program *program,
+                                                      ProgramState *state,
+                                                      const uint8_t *binary,
+                                                      size_t length,
+                                                      InfoLog &infoLog);
 
     static void ComputeHash(const Context *context, const Program *program, ProgramHash *hashOut);
 
     // Check if the cache contains a binary matching the specified program.
     bool get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut);
 
     // For querying the contents of the cache.
     bool getAt(size_t index, ProgramHash *hashOut, const angle::MemoryBuffer **programOut);
--- a/gfx/angle/checkout/src/libANGLE/Program.cpp
+++ b/gfx/angle/checkout/src/libANGLE/Program.cpp
@@ -1285,17 +1285,17 @@ bool Program::isLinked() const
 
 void Program::resolveLinkImpl()
 {
     ASSERT(mLinkingState.get());
 
     mLinked           = mLinkingState->linkEvent->wait();
     mLinkResolved     = true;
     auto linkingState = std::move(mLinkingState);
-    if (!mLinked)
+    if (!mLinked || !linkingState->context)
     {
         return;
     }
 
     initInterfaceBlockBindings();
 
     // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
     // Only successfully linked program can replace the executables.
@@ -1438,18 +1438,21 @@ Error Program::loadBinary(const Context 
     ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
     if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
     {
         mInfoLog << "Invalid program binary format.";
         return NoError();
     }
 
     const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
-    ANGLE_TRY_RESULT(
-        MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
+
+    mLinkingState.reset(new LinkingState());
+    mLinkingState->linkEvent =
+        MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog);
+    mLinkResolved = false;
 
     // Currently we require the full shader text to compute the program hash.
     // TODO(jmadill): Store the binary in the internal program cache.
 
     for (size_t uniformBlockIndex = 0; uniformBlockIndex < mState.mUniformBlocks.size();
          ++uniformBlockIndex)
     {
         mDirtyBits.set(uniformBlockIndex);
--- a/gfx/angle/checkout/src/libANGLE/renderer/ProgramImpl.h
+++ b/gfx/angle/checkout/src/libANGLE/renderer/ProgramImpl.h
@@ -61,19 +61,19 @@ class LinkEventDone final : public LinkE
 
 class ProgramImpl : angle::NonCopyable
 {
   public:
     ProgramImpl(const gl::ProgramState &state) : mState(state) {}
     virtual ~ProgramImpl() {}
     virtual gl::Error destroy(const gl::Context *context) { return gl::NoError(); }
 
-    virtual gl::LinkResult load(const gl::Context *context,
-                                gl::InfoLog &infoLog,
-                                gl::BinaryInputStream *stream) = 0;
+    virtual std::unique_ptr<LinkEvent> load(const gl::Context *context,
+                                            gl::InfoLog &infoLog,
+                                            gl::BinaryInputStream *stream) = 0;
     virtual void save(const gl::Context *context, gl::BinaryOutputStream *stream) = 0;
     virtual void setBinaryRetrievableHint(bool retrievable) = 0;
     virtual void setSeparable(bool separable)               = 0;
 
     virtual std::unique_ptr<LinkEvent> link(const gl::Context *context,
                                             const gl::ProgramLinkedResources &resources,
                                             gl::InfoLog &infoLog)          = 0;
     virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0;
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -578,25 +578,26 @@ bool ProgramD3D::usesPointSpriteEmulatio
     return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
 }
 
 bool ProgramD3D::usesGeometryShaderForPointSpriteEmulation() const
 {
     return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation();
 }
 
-bool ProgramD3D::usesGeometryShader(gl::PrimitiveMode drawMode) const
+bool ProgramD3D::usesGeometryShader(const gl::Context *context,
+                                    gl::PrimitiveMode drawMode) const
 {
     if (mHasANGLEMultiviewEnabled && !mRenderer->canSelectViewInVertexShader())
     {
         return true;
     }
     if (drawMode != gl::PrimitiveMode::Points)
     {
-        return mUsesFlatInterpolation;
+        return !context->provokingVertexDontCare() && mUsesFlatInterpolation;
     }
     return usesGeometryShaderForPointSpriteEmulation();
 }
 
 bool ProgramD3D::usesInstancedPointSpriteEmulation() const
 {
     return mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
 }
@@ -730,40 +731,284 @@ gl::RangeUI ProgramD3D::getUsedImageRang
             return readonly ? mUsedComputeReadonlyImageRange : mUsedComputeImageRange;
         // TODO(xinghua.cao@intel.com): add image range of vertex shader and pixel shader.
         default:
             UNREACHABLE();
             return {0, 0};
     }
 }
 
-gl::LinkResult ProgramD3D::load(const gl::Context *context,
-                                gl::InfoLog &infoLog,
-                                gl::BinaryInputStream *stream)
+class ProgramD3D::GetExecutableTask : public Closure
+{
+public:
+    GetExecutableTask(ProgramD3D *program, const gl::Context *context)
+        : mProgram(program),
+        mResult(angle::Result::Continue()),
+        mInfoLog(),
+        mExecutable(nullptr),
+        mContext(context)
+    {
+    }
+
+    virtual angle::Result run() = 0;
+
+    void operator()() override { mResult = run(); }
+
+    angle::Result getResult() const { return mResult; }
+    const gl::InfoLog &getInfoLog() const { return mInfoLog; }
+    ShaderExecutableD3D *getExecutable() { return mExecutable; }
+
+protected:
+    ProgramD3D * mProgram;
+    angle::Result mResult;
+    gl::InfoLog mInfoLog;
+    ShaderExecutableD3D *mExecutable;
+    const gl::Context *mContext;
+};
+
+class ProgramD3D::GetLoadExecutableTask : public ProgramD3D::GetExecutableTask
+{
+public:
+    GetLoadExecutableTask(ProgramD3D *program, const gl::Context *context,
+                          const unsigned char* shaderFunction, unsigned int shaderSize,
+                          bool separateAttribs)
+        : GetExecutableTask(program, context)
+        , mShaderFunction(shaderFunction)
+        , mShaderSize(shaderSize)
+        , mSeparateAttribs(separateAttribs)
+    {
+    }
+
+    void InternalizeData()
+    {
+        mOwnedData.assign(mShaderFunction, mShaderFunction + mShaderSize);
+        mShaderFunction = mOwnedData.data();
+    }
+
+    const unsigned char *mShaderFunction;
+    const unsigned int mShaderSize;
+    const bool mSeparateAttribs;
+    std::vector<unsigned char> mOwnedData;
+};
+
+class ProgramD3D::GetLoadVertexExecutableTask : public ProgramD3D::GetLoadExecutableTask
+{
+public:
+    GetLoadVertexExecutableTask(ProgramD3D *program, const gl::Context *context,
+                                const unsigned char* shaderFunction, unsigned int shaderSize,
+                                bool separateAttribs, gl::InputLayout& layout)
+        : GetLoadExecutableTask(program, context, shaderFunction, shaderSize, separateAttribs)
+        , mLayout(layout)
+    {
+    }
+    angle::Result run() override
+    {
+        ANGLE_TRY(
+            mProgram->loadVertexExecutable(mContext, &mExecutable, mShaderFunction,
+                                           mShaderSize, mSeparateAttribs, mLayout));
+
+        return angle::Result::Continue();
+    }
+
+    gl::InputLayout mLayout;
+};
+
+class ProgramD3D::GetLoadPixelExecutableTask : public ProgramD3D::GetLoadExecutableTask
+{
+public:
+    GetLoadPixelExecutableTask(ProgramD3D *program, const gl::Context *context,
+                               const unsigned char* shaderFunction, unsigned int shaderSize,
+                               bool separateAttribs, std::vector<GLenum>& outputs)
+        : GetLoadExecutableTask(program, context, shaderFunction, shaderSize, separateAttribs)
+        , mOutputs(outputs)
+    {
+    }
+    angle::Result run() override
+    {
+        ANGLE_TRY(
+            mProgram->loadPixelExecutable(mContext, &mExecutable, mShaderFunction,
+                                          mShaderSize, mSeparateAttribs, mOutputs));
+
+        return angle::Result::Continue();
+    }
+
+    std::vector<GLenum> mOutputs;
+};
+
+angle::Result ProgramD3D::loadVertexExecutable(const gl::Context *context,
+                                               ShaderExecutableD3D **outExecutable,
+                                               const unsigned char *shaderFunction,
+                                               unsigned int shaderSize,
+                                               bool separateAttribs,
+                                               gl::InputLayout& layout)
+{
+    ANGLE_TRY(mRenderer->loadExecutable(context, shaderFunction, shaderSize,
+                                        gl::ShaderType::Vertex, mStreamOutVaryings,
+                                        separateAttribs, outExecutable));
+
+    // generated converted input layout
+    VertexExecutable::Signature signature;
+    VertexExecutable::getSignature(mRenderer, layout, &signature);
+
+    // add new binary
+    mVertexExecutables.push_back(std::unique_ptr<VertexExecutable>(
+        new VertexExecutable(layout, signature, *outExecutable)));
+
+    return angle::Result::Continue();
+}
+
+angle::Result ProgramD3D::loadPixelExecutable(const gl::Context *context,
+                                              ShaderExecutableD3D **outExecutable,
+                                              const unsigned char *shaderFunction,
+                                              unsigned int shaderSize,
+                                              bool separateAttribs,
+                                              std::vector<GLenum>& outputs)
+{
+    ANGLE_TRY(mRenderer->loadExecutable(context, shaderFunction, shaderSize,
+                                        gl::ShaderType::Fragment, mStreamOutVaryings,
+                                        separateAttribs, outExecutable));
+
+    // add new binary
+    mPixelExecutables.push_back(
+        std::unique_ptr<PixelExecutable>(new PixelExecutable(outputs, *outExecutable)));
+
+    return angle::Result::Continue();
+}
+
+// The LinkEvent implementation for linking a rendering(VS, FS, GS) program.
+class ProgramD3D::GraphicsProgramLinkEvent final : public LinkEvent
+{
+public:
+    GraphicsProgramLinkEvent(gl::InfoLog &infoLog,
+        std::shared_ptr<WorkerThreadPool> workerPool,
+        std::shared_ptr<ProgramD3D::GetExecutableTask> vertexTask,
+        std::shared_ptr<ProgramD3D::GetExecutableTask> pixelTask,
+        std::shared_ptr<ProgramD3D::GetExecutableTask> geometryTask,
+        bool useGS,
+        const ShaderD3D *vertexShader,
+        const ShaderD3D *fragmentShader)
+        : mInfoLog(infoLog),
+        mWorkerPool(workerPool),
+        mVertexTask(vertexTask),
+        mPixelTask(pixelTask),
+        mGeometryTask(geometryTask),
+        mWaitEvents(
+            { { std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mVertexTask)),
+            std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mPixelTask)),
+            std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mGeometryTask)) } }),
+        mUseGS(useGS),
+        mVertexShader(vertexShader),
+        mFragmentShader(fragmentShader)
+    {
+    }
+
+    bool wait() override
+    {
+        WaitableEvent::WaitMany(&mWaitEvents);
+
+        if (!checkTask(mVertexTask.get()) || !checkTask(mPixelTask.get()) ||
+            !checkTask(mGeometryTask.get()))
+        {
+            return false;
+        }
+
+        ShaderExecutableD3D *defaultVertexExecutable = mVertexTask->getExecutable();
+        ShaderExecutableD3D *defaultPixelExecutable = mPixelTask->getExecutable();
+        ShaderExecutableD3D *pointGS = mGeometryTask->getExecutable();
+
+        if (mUseGS && pointGS)
+        {
+            // Geometry shaders are currently only used internally, so there is no corresponding
+            // shader object at the interface level. For now the geometry shader debug info is
+            // prepended to the vertex shader.
+            mVertexShader->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n");
+            mVertexShader->appendDebugInfo(pointGS->getDebugInfo());
+            mVertexShader->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n");
+        }
+
+        if (defaultVertexExecutable && mVertexShader)
+        {
+            mVertexShader->appendDebugInfo(defaultVertexExecutable->getDebugInfo());
+        }
+
+        if (defaultPixelExecutable && mFragmentShader)
+        {
+            mFragmentShader->appendDebugInfo(defaultPixelExecutable->getDebugInfo());
+        }
+
+        bool isLinked = (defaultVertexExecutable && defaultPixelExecutable && (!mUseGS || pointGS));
+        if (!isLinked)
+        {
+            mInfoLog << "Failed to create D3D Shaders";
+        }
+        return isLinked;
+    }
+
+    bool isLinking() override
+    {
+        for (auto &event : mWaitEvents)
+        {
+            if (!event->isReady())
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+private:
+    bool checkTask(ProgramD3D::GetExecutableTask *task)
+    {
+        if (!task->getInfoLog().empty())
+        {
+            mInfoLog << task->getInfoLog().str();
+        }
+        auto result = task->getResult();
+        if (result.isError())
+        {
+            return false;
+        }
+        return true;
+    }
+
+    gl::InfoLog &mInfoLog;
+    std::shared_ptr<WorkerThreadPool> mWorkerPool;
+    std::shared_ptr<ProgramD3D::GetExecutableTask> mVertexTask;
+    std::shared_ptr<ProgramD3D::GetExecutableTask> mPixelTask;
+    std::shared_ptr<ProgramD3D::GetExecutableTask> mGeometryTask;
+    std::array<std::shared_ptr<WaitableEvent>, 3> mWaitEvents;
+    bool mUseGS;
+    const ShaderD3D *mVertexShader;
+    const ShaderD3D *mFragmentShader;
+};
+
+std::unique_ptr<LinkEvent> ProgramD3D::load(const gl::Context *context,
+                                            gl::InfoLog &infoLog,
+                                            gl::BinaryInputStream *stream)
 {
     // TODO(jmadill): Use Renderer from contextImpl.
 
     reset();
 
     DeviceIdentifier binaryDeviceIdentifier = {0};
     stream->readBytes(reinterpret_cast<unsigned char *>(&binaryDeviceIdentifier),
                       sizeof(DeviceIdentifier));
 
     DeviceIdentifier identifier = mRenderer->getAdapterIdentifier();
     if (memcmp(&identifier, &binaryDeviceIdentifier, sizeof(DeviceIdentifier)) != 0)
     {
         infoLog << "Invalid program binary, device configuration has changed.";
-        return false;
+        return std::make_unique<LinkEventDone>(false);
     }
 
     int compileFlags = stream->readInt<int>();
     if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
     {
         infoLog << "Mismatched compilation flags.";
-        return false;
+        return std::make_unique<LinkEventDone>(false);
     }
 
     for (int &index : mAttribLocationToD3DSemantic)
     {
         stream->readInt(&index);
     }
 
     for (gl::ShaderType shaderType : gl::AllShaderTypes())
@@ -811,17 +1056,17 @@ gl::LinkResult ProgramD3D::load(const gl
     mUsedComputeImageRange = gl::RangeUI(computeImageRangeLow, computeImageRangeHigh);
     mUsedComputeReadonlyImageRange =
         gl::RangeUI(computeReadonlyImageRangeLow, computeReadonlyImageRangeHigh);
 
     const unsigned int uniformCount = stream->readInt<unsigned int>();
     if (stream->error())
     {
         infoLog << "Invalid program binary.";
-        return false;
+        return std::make_unique<LinkEventDone>(false);
     }
 
     const auto &linkedUniforms = mState.getUniforms();
     ASSERT(mD3DUniforms.empty());
     for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
     {
         const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex];
 
@@ -838,17 +1083,17 @@ gl::LinkResult ProgramD3D::load(const gl
 
         mD3DUniforms.push_back(d3dUniform);
     }
 
     const unsigned int blockCount = stream->readInt<unsigned int>();
     if (stream->error())
     {
         infoLog << "Invalid program binary.";
-        return false;
+        return std::make_unique<LinkEventDone>(false);
     }
 
     ASSERT(mD3DUniformBlocks.empty());
     for (unsigned int blockIndex = 0; blockIndex < blockCount; ++blockIndex)
     {
         D3DUniformBlock uniformBlock;
         for (gl::ShaderType shaderType : gl::AllShaderTypes())
         {
@@ -894,135 +1139,155 @@ gl::LinkResult ProgramD3D::load(const gl
     }
 
     stream->readString(&mGeometryShaderPreamble);
 
     const unsigned char *binary = reinterpret_cast<const unsigned char *>(stream->data());
 
     bool separateAttribs = (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS);
 
+    std::vector<std::shared_ptr<GetLoadExecutableTask>> tasks;
+    auto FlushTasks = [&]() {
+        for (auto& task : tasks) {
+            angle::Result result = task->run();
+
+            if (result.isError()) {
+                return std::make_unique<LinkEventDone>(result);
+            }
+
+            ShaderExecutableD3D *shaderExecutable = task->getExecutable();
+
+            if (!shaderExecutable)
+            {
+                infoLog << "Could not create shader.";
+                return std::make_unique<LinkEventDone>(false);
+            }
+        }
+        tasks.clear();
+        return std::unique_ptr<LinkEventDone>(nullptr);
+    };
+
     const unsigned int vertexShaderCount = stream->readInt<unsigned int>();
     for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount;
          vertexShaderIndex++)
     {
         size_t inputLayoutSize = stream->readInt<size_t>();
         gl::InputLayout inputLayout(inputLayoutSize, gl::VERTEX_FORMAT_INVALID);
 
         for (size_t inputIndex = 0; inputIndex < inputLayoutSize; inputIndex++)
         {
             inputLayout[inputIndex] = stream->readInt<gl::VertexFormatType>();
         }
 
-        unsigned int vertexShaderSize             = stream->readInt<unsigned int>();
+        unsigned int vertexShaderSize = stream->readInt<unsigned int>();
         const unsigned char *vertexShaderFunction = binary + stream->offset();
 
-        ShaderExecutableD3D *shaderExecutable = nullptr;
-
-        ANGLE_TRY(mRenderer->loadExecutable(context, vertexShaderFunction, vertexShaderSize,
-                                            gl::ShaderType::Vertex, mStreamOutVaryings,
-                                            separateAttribs, &shaderExecutable));
-
-        if (!shaderExecutable)
-        {
-            infoLog << "Could not create vertex shader.";
-            return false;
-        }
-
-        // generated converted input layout
-        VertexExecutable::Signature signature;
-        VertexExecutable::getSignature(mRenderer, inputLayout, &signature);
-
-        // add new binary
-        mVertexExecutables.push_back(std::unique_ptr<VertexExecutable>(
-            new VertexExecutable(inputLayout, signature, shaderExecutable)));
-
+        tasks.emplace_back(std::make_shared<GetLoadVertexExecutableTask>(this, context, vertexShaderFunction,
+                                                                         vertexShaderSize, separateAttribs, inputLayout));
         stream->skip(vertexShaderSize);
     }
 
     const size_t pixelShaderCount = stream->readInt<unsigned int>();
     for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
     {
         const size_t outputCount = stream->readInt<unsigned int>();
         std::vector<GLenum> outputs(outputCount);
         for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
         {
             stream->readInt(&outputs[outputIndex]);
         }
 
         const size_t pixelShaderSize             = stream->readInt<unsigned int>();
         const unsigned char *pixelShaderFunction = binary + stream->offset();
-        ShaderExecutableD3D *shaderExecutable    = nullptr;
-
-        ANGLE_TRY(mRenderer->loadExecutable(context, pixelShaderFunction, pixelShaderSize,
-                                            gl::ShaderType::Fragment, mStreamOutVaryings,
-                                            separateAttribs, &shaderExecutable));
-
-        if (!shaderExecutable)
-        {
-            infoLog << "Could not create pixel shader.";
-            return false;
-        }
-
-        // add new binary
-        mPixelExecutables.push_back(
-            std::unique_ptr<PixelExecutable>(new PixelExecutable(outputs, shaderExecutable)));
-
+
+        tasks.emplace_back(std::make_shared<GetLoadPixelExecutableTask>(this, context, pixelShaderFunction,
+                                                                        pixelShaderSize, separateAttribs, outputs));
         stream->skip(pixelShaderSize);
     }
 
     for (auto &geometryExe : mGeometryExecutables)
     {
         unsigned int geometryShaderSize = stream->readInt<unsigned int>();
         if (geometryShaderSize == 0)
         {
             continue;
         }
 
+        auto failure = FlushTasks();
+        if (failure) {
+            return std::move(failure);
+        }
+
         const unsigned char *geometryShaderFunction = binary + stream->offset();
 
         ShaderExecutableD3D *geometryExecutable = nullptr;
-        ANGLE_TRY(mRenderer->loadExecutable(context, geometryShaderFunction, geometryShaderSize,
-                                            gl::ShaderType::Geometry, mStreamOutVaryings,
-                                            separateAttribs, &geometryExecutable));
+        angle::Result result = mRenderer->loadExecutable(context, geometryShaderFunction, geometryShaderSize,
+                                                         gl::ShaderType::Geometry, mStreamOutVaryings,
+                                                         separateAttribs, &geometryExecutable);
+        if (result.isError()) {
+            return std::make_unique<LinkEventDone>(result);
+        }
 
         if (!geometryExecutable)
         {
             infoLog << "Could not create geometry shader.";
-            return false;
+            return std::make_unique<LinkEventDone>(false);
         }
 
         geometryExe.reset(geometryExecutable);
 
         stream->skip(geometryShaderSize);
     }
 
     unsigned int computeShaderSize = stream->readInt<unsigned int>();
     if (computeShaderSize > 0)
     {
+        auto failure = FlushTasks();
+        if (failure) {
+            return std::move(failure);
+        }
+
         const unsigned char *computeShaderFunction = binary + stream->offset();
 
         ShaderExecutableD3D *computeExecutable = nullptr;
-        ANGLE_TRY(mRenderer->loadExecutable(context, computeShaderFunction, computeShaderSize,
-                                            gl::ShaderType::Compute, std::vector<D3DVarying>(),
-                                            false, &computeExecutable));
+        angle::Result result = mRenderer->loadExecutable(context, computeShaderFunction, computeShaderSize,
+                                                         gl::ShaderType::Compute, std::vector<D3DVarying>(),
+                                                         false, &computeExecutable);
+        if (result.isError()) {
+            return std::make_unique<LinkEventDone>(result);
+        }
 
         if (!computeExecutable)
         {
             infoLog << "Could not create compute shader.";
-            return false;
+            return std::make_unique<LinkEventDone>(false);
         }
 
         mComputeExecutable.reset(computeExecutable);
     }
 
     initializeUniformStorage(mState.getLinkedShaderStages());
 
     dirtyAllUniforms();
 
-    return true;
+    if (tasks.size() == 2 && vertexShaderCount == 1 && pixelShaderCount == 1) {
+        auto geometryTask = std::make_shared<GetGeometryExecutableTask>(this, context);
+        tasks[0]->InternalizeData();
+        tasks[1]->InternalizeData();
+        return std::make_unique<GraphicsProgramLinkEvent>(infoLog, context->getWorkerThreadPool(),
+            tasks[0], tasks[1], geometryTask, false,
+            nullptr, nullptr);
+    } else {
+        auto result = FlushTasks();
+        if (result) {
+          return std::move(result);
+        }
+    }
+
+    return std::make_unique<LinkEventDone>(true);
 }
 
 void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream)
 {
     // Output the DeviceIdentifier before we output any shader code
     // When we load the binary again later, we can validate the device identifier before trying to
     // compile any HLSL
     DeviceIdentifier binaryIdentifier = mRenderer->getAdapterIdentifier();
@@ -1292,17 +1557,17 @@ angle::Result ProgramD3D::getGeometryExe
                                                                 gl::InfoLog *infoLog)
 {
     if (outExecutable)
     {
         *outExecutable = nullptr;
     }
 
     // Return a null shader if the current rendering doesn't use a geometry shader
-    if (!usesGeometryShader(drawMode))
+    if (!usesGeometryShader(context, drawMode))
     {
         return angle::Result::Continue();
     }
 
     gl::PrimitiveMode geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode);
 
     if (mGeometryExecutables[geometryShaderType])
     {
@@ -1340,43 +1605,16 @@ angle::Result ProgramD3D::getGeometryExe
 
     if (outExecutable)
     {
         *outExecutable = mGeometryExecutables[geometryShaderType].get();
     }
     return result;
 }
 
-class ProgramD3D::GetExecutableTask : public Closure
-{
-  public:
-    GetExecutableTask(ProgramD3D *program, const gl::Context *context)
-        : mProgram(program),
-          mResult(angle::Result::Continue()),
-          mInfoLog(),
-          mExecutable(nullptr),
-          mContext(context)
-    {
-    }
-
-    virtual angle::Result run() = 0;
-
-    void operator()() override { mResult = run(); }
-
-    angle::Result getResult() const { return mResult; }
-    const gl::InfoLog &getInfoLog() const { return mInfoLog; }
-    ShaderExecutableD3D *getExecutable() { return mExecutable; }
-
-  protected:
-    ProgramD3D *mProgram;
-    angle::Result mResult;
-    gl::InfoLog mInfoLog;
-    ShaderExecutableD3D *mExecutable;
-    const gl::Context *mContext;
-};
 
 class ProgramD3D::GetVertexExecutableTask : public ProgramD3D::GetExecutableTask
 {
   public:
     GetVertexExecutableTask(ProgramD3D *program, const gl::Context *context)
         : GetExecutableTask(program, context)
     {
     }
@@ -1430,17 +1668,17 @@ class ProgramD3D::GetGeometryExecutableT
         : GetExecutableTask(program, context)
     {
     }
 
     angle::Result run() override
     {
         // Auto-generate the geometry shader here, if we expect to be using point rendering in
         // D3D11.
-        if (mProgram->usesGeometryShader(gl::PrimitiveMode::Points))
+        if (mProgram->usesGeometryShader(mContext, gl::PrimitiveMode::Points))
         {
             ANGLE_TRY(mProgram->getGeometryExecutableForPrimitiveType(
                 mContext, gl::PrimitiveMode::Points, &mExecutable, &mInfoLog));
         }
 
         return angle::Result::Continue();
     }
 };
@@ -1450,137 +1688,31 @@ angle::Result ProgramD3D::getComputeExec
     if (outExecutable)
     {
         *outExecutable = mComputeExecutable.get();
     }
 
     return angle::Result::Continue();
 }
 
-// The LinkEvent implementation for linking a rendering(VS, FS, GS) program.
-class ProgramD3D::GraphicsProgramLinkEvent final : public LinkEvent
-{
-  public:
-    GraphicsProgramLinkEvent(gl::InfoLog &infoLog,
-                             std::shared_ptr<WorkerThreadPool> workerPool,
-                             std::shared_ptr<ProgramD3D::GetVertexExecutableTask> vertexTask,
-                             std::shared_ptr<ProgramD3D::GetPixelExecutableTask> pixelTask,
-                             std::shared_ptr<ProgramD3D::GetGeometryExecutableTask> geometryTask,
-                             bool useGS,
-                             const ShaderD3D *vertexShader,
-                             const ShaderD3D *fragmentShader)
-        : mInfoLog(infoLog),
-          mWorkerPool(workerPool),
-          mVertexTask(vertexTask),
-          mPixelTask(pixelTask),
-          mGeometryTask(geometryTask),
-          mWaitEvents(
-              {{std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mVertexTask)),
-                std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mPixelTask)),
-                std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mGeometryTask))}}),
-          mUseGS(useGS),
-          mVertexShader(vertexShader),
-          mFragmentShader(fragmentShader)
-    {
-    }
-
-    bool wait() override
-    {
-        WaitableEvent::WaitMany(&mWaitEvents);
-
-        if (!checkTask(mVertexTask.get()) || !checkTask(mPixelTask.get()) ||
-            !checkTask(mGeometryTask.get()))
-        {
-            return false;
-        }
-
-        ShaderExecutableD3D *defaultVertexExecutable = mVertexTask->getExecutable();
-        ShaderExecutableD3D *defaultPixelExecutable  = mPixelTask->getExecutable();
-        ShaderExecutableD3D *pointGS                 = mGeometryTask->getExecutable();
-
-        if (mUseGS && pointGS)
-        {
-            // Geometry shaders are currently only used internally, so there is no corresponding
-            // shader object at the interface level. For now the geometry shader debug info is
-            // prepended to the vertex shader.
-            mVertexShader->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n");
-            mVertexShader->appendDebugInfo(pointGS->getDebugInfo());
-            mVertexShader->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n");
-        }
-
-        if (defaultVertexExecutable)
-        {
-            mVertexShader->appendDebugInfo(defaultVertexExecutable->getDebugInfo());
-        }
-
-        if (defaultPixelExecutable)
-        {
-            mFragmentShader->appendDebugInfo(defaultPixelExecutable->getDebugInfo());
-        }
-
-        bool isLinked = (defaultVertexExecutable && defaultPixelExecutable && (!mUseGS || pointGS));
-        if (!isLinked)
-        {
-            mInfoLog << "Failed to create D3D Shaders";
-        }
-        return isLinked;
-    }
-
-    bool isLinking() override
-    {
-        for (auto &event : mWaitEvents)
-        {
-            if (!event->isReady())
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-  private:
-    bool checkTask(ProgramD3D::GetExecutableTask *task)
-    {
-        if (!task->getInfoLog().empty())
-        {
-            mInfoLog << task->getInfoLog().str();
-        }
-        auto result = task->getResult();
-        if (result.isError())
-        {
-            return false;
-        }
-        return true;
-    }
-
-    gl::InfoLog &mInfoLog;
-    std::shared_ptr<WorkerThreadPool> mWorkerPool;
-    std::shared_ptr<ProgramD3D::GetVertexExecutableTask> mVertexTask;
-    std::shared_ptr<ProgramD3D::GetPixelExecutableTask> mPixelTask;
-    std::shared_ptr<ProgramD3D::GetGeometryExecutableTask> mGeometryTask;
-    std::array<std::shared_ptr<WaitableEvent>, 3> mWaitEvents;
-    bool mUseGS;
-    const ShaderD3D *mVertexShader;
-    const ShaderD3D *mFragmentShader;
-};
 
 std::unique_ptr<LinkEvent> ProgramD3D::compileProgramExecutables(const gl::Context *context,
                                                                  gl::InfoLog &infoLog)
 {
     // Ensure the compiler is initialized to avoid race conditions.
     gl::Error result = mRenderer->ensureHLSLCompilerInitialized(context);
     if (result.isError())
     {
         return std::make_unique<LinkEventDone>(result);
     }
 
     auto vertexTask   = std::make_shared<GetVertexExecutableTask>(this, context);
     auto pixelTask    = std::make_shared<GetPixelExecutableTask>(this, context);
     auto geometryTask = std::make_shared<GetGeometryExecutableTask>(this, context);
-    bool useGS        = usesGeometryShader(gl::PrimitiveMode::Points);
+    bool useGS        = usesGeometryShader(context, gl::PrimitiveMode::Points);
     const ShaderD3D *vertexShaderD3D =
         GetImplAs<ShaderD3D>(mState.getAttachedShader(gl::ShaderType::Vertex));
     const ShaderD3D *fragmentShaderD3D =
         GetImplAs<ShaderD3D>(mState.getAttachedShader(gl::ShaderType::Fragment));
 
     return std::make_unique<GraphicsProgramLinkEvent>(infoLog, context->getWorkerThreadPool(),
                                                       vertexTask, pixelTask, geometryTask, useGS,
                                                       vertexShaderD3D, fragmentShaderD3D);
@@ -2753,19 +2885,20 @@ void ProgramD3D::setPathFragmentInputGen
     UNREACHABLE();
 }
 
 bool ProgramD3D::hasVertexExecutableForCachedInputLayout()
 {
     return mCachedVertexExecutableIndex.valid();
 }
 
-bool ProgramD3D::hasGeometryExecutableForPrimitiveType(gl::PrimitiveMode drawMode)
+bool ProgramD3D::hasGeometryExecutableForPrimitiveType(const gl::Context* context,
+                                                       gl::PrimitiveMode drawMode)
 {
-    if (!usesGeometryShader(drawMode))
+    if (!usesGeometryShader(context, drawMode))
     {
         // No shader necessary mean we have the required (null) executable.
         return true;
     }
 
     gl::PrimitiveMode geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode);
     return mGeometryExecutables[geometryShaderType].get() != nullptr;
 }
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -169,37 +169,50 @@ class ProgramD3D : public ProgramImpl
     GLint getImageMapping(gl::ShaderType type,
                           unsigned int imageIndex,
                           bool readonly,
                           const gl::Caps &caps) const;
     gl::RangeUI getUsedImageRange(gl::ShaderType type, bool readonly) const;
 
     bool usesPointSize() const { return mUsesPointSize; }
     bool usesPointSpriteEmulation() const;
-    bool usesGeometryShader(gl::PrimitiveMode drawMode) const;
+	bool usesGeometryShader(const gl::Context *context,
+		                    gl::PrimitiveMode drawMode) const;
     bool usesGeometryShaderForPointSpriteEmulation() const;
     bool usesInstancedPointSpriteEmulation() const;
 
-    gl::LinkResult load(const gl::Context *context,
-                        gl::InfoLog &infoLog,
-                        gl::BinaryInputStream *stream) override;
+    std::unique_ptr<LinkEvent> load(const gl::Context *context,
+                                    gl::InfoLog &infoLog,
+                                    gl::BinaryInputStream *stream) override;
     void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
     void setBinaryRetrievableHint(bool retrievable) override;
     void setSeparable(bool separable) override;
 
     angle::Result getVertexExecutableForCachedInputLayout(const gl::Context *context,
                                                           ShaderExecutableD3D **outExectuable,
                                                           gl::InfoLog *infoLog);
     angle::Result getGeometryExecutableForPrimitiveType(const gl::Context *context,
                                                         gl::PrimitiveMode drawMode,
                                                         ShaderExecutableD3D **outExecutable,
                                                         gl::InfoLog *infoLog);
     angle::Result getPixelExecutableForCachedOutputLayout(const gl::Context *context,
                                                           ShaderExecutableD3D **outExectuable,
                                                           gl::InfoLog *infoLog);
+    angle::Result loadVertexExecutable(const gl::Context *context,
+                                       ShaderExecutableD3D **outExecutable,
+                                       const unsigned char *shaderFunction,
+                                       unsigned int shaderSize,
+                                       bool separateAttribs,
+                                       gl::InputLayout& layout);
+    angle::Result loadPixelExecutable(const gl::Context *context,
+                                      ShaderExecutableD3D **outExecutable,
+                                      const unsigned char *shaderFunction,
+                                      unsigned int shaderSize,
+                                      bool separateAttribs,
+                                      std::vector<GLenum>& layout);
     angle::Result getComputeExecutable(ShaderExecutableD3D **outExecutable);
     std::unique_ptr<LinkEvent> link(const gl::Context *context,
                                     const gl::ProgramLinkedResources &resources,
                                     gl::InfoLog &infoLog) override;
     GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
 
     void setPathFragmentInputGen(const std::string &inputName,
                                  GLenum genMode,
@@ -279,17 +292,18 @@ class ProgramD3D : public ProgramImpl
 
     void updateCachedInputLayout(Serial associatedSerial, const gl::State &state);
     void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer);
 
     bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
 
     // Checks if we need to recompile certain shaders.
     bool hasVertexExecutableForCachedInputLayout();
-    bool hasGeometryExecutableForPrimitiveType(gl::PrimitiveMode drawMode);
+    bool hasGeometryExecutableForPrimitiveType(const gl::Context *context,
+                                               gl::PrimitiveMode drawMode);
     bool hasPixelExecutableForCachedOutputLayout();
 
     bool anyShaderUniformsDirty() const { return mShaderUniformsDirty.any(); }
 
     bool areShaderUniformsDirty(gl::ShaderType shaderType) const
     {
         return mShaderUniformsDirty[shaderType];
     }
@@ -304,16 +318,19 @@ class ProgramD3D : public ProgramImpl
     }
 
   private:
     // These forward-declared tasks are used for multi-thread shader compiles.
     class GetExecutableTask;
     class GetVertexExecutableTask;
     class GetPixelExecutableTask;
     class GetGeometryExecutableTask;
+    class GetLoadExecutableTask;
+    class GetLoadVertexExecutableTask;
+    class GetLoadPixelExecutableTask;
     class GraphicsProgramLinkEvent;
 
     class VertexExecutable
     {
       public:
         enum HLSLAttribType
         {
             FLOAT,
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
@@ -497,17 +497,17 @@ angle::Result Context11::triggerDrawCall
     const auto *drawFBO    = glState.getDrawFramebuffer();
     gl::Program *program   = glState.getProgram();
     ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
 
     programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
     programD3D->updateCachedOutputLayout(context, drawFBO);
 
     bool recompileVS = !programD3D->hasVertexExecutableForCachedInputLayout();
-    bool recompileGS = !programD3D->hasGeometryExecutableForPrimitiveType(drawMode);
+    bool recompileGS = !programD3D->hasGeometryExecutableForPrimitiveType(context, drawMode);
     bool recompilePS = !programD3D->hasPixelExecutableForCachedOutputLayout();
 
     if (!recompileVS && !recompileGS && !recompilePS)
     {
         return angle::Result::Continue();
     }
 
     // Load the compiler if necessary and recompile the programs.
@@ -528,17 +528,17 @@ angle::Result Context11::triggerDrawCall
         }
     }
 
     if (recompileGS)
     {
         ShaderExecutableD3D *geometryExe = nullptr;
         ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe,
                                                                     &infoLog));
-        if (!programD3D->hasGeometryExecutableForPrimitiveType(drawMode))
+        if (!programD3D->hasGeometryExecutableForPrimitiveType(context, drawMode))
         {
             ASSERT(infoLog.getLength() > 0);
             ERR() << "Error compiling dynamic geometry executable: " << infoLog.str();
             ANGLE_TRY_HR(this, E_FAIL, "Error compiling dynamic geometry executable");
         }
     }
 
     if (recompilePS)
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1460,17 +1460,17 @@ angle::Result Renderer11::drawArrays(con
     // Note: vertex indexes can be arbitrarily large.
     UINT clampedVertexCount = params.getClampedVertexCount<UINT>();
 
     const auto &glState = context->getGLState();
     if (glState.getCurrentTransformFeedback() && glState.isTransformFeedbackActiveUnpaused())
     {
         ANGLE_TRY(markTransformFeedbackUsage(context));
 
-        if (programD3D->usesGeometryShader(params.mode()))
+        if (programD3D->usesGeometryShader(context, params.mode()))
         {
             return drawWithGeometryShaderAndTransformFeedback(
                 context, params.mode(), adjustedInstanceCount, clampedVertexCount);
         }
     }
 
     switch (params.mode())
     {
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -2655,17 +2655,17 @@ angle::Result StateManager11::syncProgra
     ANGLE_TRY(context11->triggerDrawCallProgramRecompilation(context, drawMode));
 
     const auto &glState = context->getGLState();
 
     mProgramD3D->updateCachedInputLayout(mVertexArray11->getCurrentStateSerial(), glState);
 
     // Binaries must be compiled before the sync.
     ASSERT(mProgramD3D->hasVertexExecutableForCachedInputLayout());
-    ASSERT(mProgramD3D->hasGeometryExecutableForPrimitiveType(drawMode));
+    ASSERT(mProgramD3D->hasGeometryExecutableForPrimitiveType(context, drawMode));
     ASSERT(mProgramD3D->hasPixelExecutableForCachedOutputLayout());
 
     ShaderExecutableD3D *vertexExe = nullptr;
     ANGLE_TRY(mProgramD3D->getVertexExecutableForCachedInputLayout(context, &vertexExe, nullptr));
 
     ShaderExecutableD3D *pixelExe = nullptr;
     ANGLE_TRY(mProgramD3D->getPixelExecutableForCachedOutputLayout(context, &pixelExe, nullptr));
 
--- a/gfx/angle/checkout/src/libANGLE/validationEGL.cpp
+++ b/gfx/angle/checkout/src/libANGLE/validationEGL.cpp
@@ -979,16 +979,30 @@ Error ValidateCreateContext(Display *dis
                 }
                 if (value != EGL_TRUE && value != EGL_FALSE)
                 {
                     return EglBadAttribute() << "EGL_EXTENSIONS_ENABLED_ANGLE must be "
                                                 "either EGL_TRUE or EGL_FALSE.";
                 }
                 break;
 
+            case EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ:
+                if (!display->getExtensions().provokingVertexDontCare)
+                {
+                    return EglBadAttribute()
+                           << "Attribute EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ "
+                              "requires EGL_MOZ_create_context_provoking_vertex_dont_care.";
+                }
+                if (value != EGL_TRUE && value != EGL_FALSE)
+                {
+                    return EglBadAttribute() << "EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ "
+                                              "must be either EGL_TRUE or EGL_FALSE.";
+                }
+                break;
+
             default:
                 return EglBadAttribute() << "Unknown attribute.";
         }
     }
 
     switch (clientMajorVersion)
     {
         case 1:
--- a/gfx/angle/cherry_picks.txt
+++ b/gfx/angle/cherry_picks.txt
@@ -1,8 +1,51 @@
+commit 598f2502e3a41b76d90037e7858c43c18e66399d
+Merge: 8212058a6 e15a25c6f
+Author: Jeff Gilbert <jdashg@gmail.com>
+Date:   Tue Oct 9 13:54:05 2018 -0700
+
+    Merge pull request #13 from mattwoodrow/async-load-program
+    
+    Support async glProgramBInary
+
+commit 8212058a6c6339ba541f9aabb076900cd31448ef
+Merge: 4fb8d7f97 895294a05
+Author: Jeff Gilbert <jdashg@gmail.com>
+Date:   Tue Oct 9 13:52:08 2018 -0700
+
+    Merge pull request #14 from mattwoodrow/provoking-vertex
+    
+    Add support for EGL_MOZ_create_context_provoking_vertex_dont_care
+
+commit 895294a057c022f0db77975a19419abbec4c9226
+Author: Dan Glastonbury <dan.glastonbury@gmail.com>
+Date:   Tue Oct 9 10:02:46 2018 +1300
+
+    Add support for EGL_MOZ_create_context_provoking_vertex_dont_care
+    extension
+
+commit e15a25c6fa1d910115ce6fd7a03fa5ffece8a054
+Author: Matt Woodrow <matt.woodrow@gmail.com>
+Date:   Tue Oct 9 09:56:16 2018 +1300
+
+    Support async Program::load for ProgramD3D.
+
+commit 2555cc62e340cef6a2744b7f52f3e8b94aa635e1
+Author: Matt Woodrow <matt.woodrow@gmail.com>
+Date:   Tue Oct 9 09:53:40 2018 +1300
+
+    Move task definitions to earlier in the file.
+
+commit 04adbfe1a2bfad21c549a0d30349d1da620e556c
+Author: Matt Woodrow <matt.woodrow@gmail.com>
+Date:   Tue Oct 9 09:52:42 2018 +1300
+
+    Make ProgramImpl::load() return a task and support asynchronously waiting for it to complete.
+
 commit 4fb8d7f978adda36086377ea7846951faa9f6bd3
 Author: Jeff Gilbert <jgilbert@mozilla.com>
 Date:   Wed Sep 26 18:04:05 2018 -0700
 
     Polyfill BitCount for ARM/ARM64 on MSVC.
     
     Also _WIN64 implies _WIN32.