Refactor HLSL compilation out of Renderer.

This moves the start-up and tear-down code for D3DCompiler.dll into an object
that Renderer9 and Renderer11 use.  This will help future efforts to remove
references to HLSL at the GL/Renderer interface level.

BUG=angle:558

Change-Id: I18fcf9b237265d69c1d7d2ea345696c8fd31df29
Reviewed-on: https://chromium-review.googlesource.com/185568
Tested-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/renderer/Renderer.cpp b/src/libGLESv2/renderer/Renderer.cpp
index 9ade993..78c4b2d 100644
--- a/src/libGLESv2/renderer/Renderer.cpp
+++ b/src/libGLESv2/renderer/Renderer.cpp
@@ -26,147 +26,9 @@
 
 Renderer::Renderer(egl::Display *display) : mDisplay(display)
 {
-    mD3dCompilerModule = NULL;
-    mD3DCompileFunc = NULL;
     mCurrentClientVersion = 2;
 }
 
-Renderer::~Renderer()
-{
-    if (mD3dCompilerModule)
-    {
-        FreeLibrary(mD3dCompilerModule);
-        mD3dCompilerModule = NULL;
-    }
-}
-
-bool Renderer::initializeCompiler()
-{
-    TRACE_EVENT0("gpu", "initializeCompiler");
-#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES)
-    // Find a D3DCompiler module that had already been loaded based on a predefined list of versions.
-    static TCHAR* d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES;
-
-    for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i)
-    {
-        if (GetModuleHandleEx(0, d3dCompilerNames[i], &mD3dCompilerModule))
-        {
-            break;
-        }
-    }
-#endif  // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES
-
-    if (!mD3dCompilerModule)
-    {
-        // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with.
-        mD3dCompilerModule = LoadLibrary(D3DCOMPILER_DLL);
-    }
-
-    if (!mD3dCompilerModule)
-    {
-        ERR("No D3D compiler module found - aborting!\n");
-        return false;
-    }
-
-    mD3DCompileFunc = reinterpret_cast<pCompileFunc>(GetProcAddress(mD3dCompilerModule, "D3DCompile"));
-    ASSERT(mD3DCompileFunc);
-
-    return mD3DCompileFunc != NULL;
-}
-
-// Compiles HLSL code into executable binaries
-ShaderBlob *Renderer::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, UINT optimizationFlags, bool alternateFlags)
-{
-    if (!hlsl)
-    {
-        return NULL;
-    }
-
-    HRESULT result = S_OK;
-    UINT flags = 0;
-    std::string sourceText;
-    if (gl::perfActive())
-    {
-        flags |= D3DCOMPILE_DEBUG;
-
-#ifdef NDEBUG
-        flags |= optimizationFlags;
-#else
-        flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
-#endif
-
-        std::string sourcePath = getTempPath();
-        sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
-        writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
-    }
-    else
-    {
-        flags |= optimizationFlags;
-        sourceText = hlsl;
-    }
-
-    // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
-    // Try the default flags first and if compilation fails, try some alternatives.
-    const static UINT extraFlags[] =
-    {
-        0,
-        D3DCOMPILE_AVOID_FLOW_CONTROL,
-        D3DCOMPILE_PREFER_FLOW_CONTROL
-    };
-
-    const static char * const extraFlagNames[] =
-    {
-        "default",
-        "avoid flow control",
-        "prefer flow control"
-    };
-
-    int attempts = alternateFlags ? ArraySize(extraFlags) : 1;
-    pD3DCompile compileFunc = reinterpret_cast<pD3DCompile>(mD3DCompileFunc);
-    for (int i = 0; i < attempts; ++i)
-    {
-        ID3DBlob *errorMessage = NULL;
-        ID3DBlob *binary = NULL;
-
-        result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL,
-                             "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage);
-        if (errorMessage)
-        {
-            const char *message = (const char*)errorMessage->GetBufferPointer();
-
-            infoLog.appendSanitized(message);
-            TRACE("\n%s", hlsl);
-            TRACE("\n%s", message);
-
-            SafeRelease(errorMessage);
-        }
-
-        if (SUCCEEDED(result))
-        {
-            return (ShaderBlob*)binary;
-        }
-        else
-        {
-            if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
-            {
-                return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*) NULL);
-            }
-
-            infoLog.append("Warning: D3D shader compilation failed with ");
-            infoLog.append(extraFlagNames[i]);
-            infoLog.append(" flags.");
-            if (i + 1 < attempts)
-            {
-                infoLog.append(" Retrying with ");
-                infoLog.append(extraFlagNames[i + 1]);
-                infoLog.append(".\n");
-            }
-        }
-    }
-
-    return NULL;
-}
-
 }
 
 extern "C"
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index fa14806..f15482c 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -65,9 +65,6 @@
 class TextureStorage;
 class UniformStorage;
 
-typedef void * ShaderBlob;
-typedef void (*pCompileFunc)();
-
 struct ConfigDesc
 {
     GLenum  renderTargetFormat;
@@ -101,7 +98,6 @@
 {
   public:
     explicit Renderer(egl::Display *display);
-    virtual ~Renderer();
 
     virtual EGLint initialize() = 0;
     virtual bool resetDevice() = 0;
@@ -276,16 +272,11 @@
     virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0;
 
   protected:
-    bool initializeCompiler();
-    ShaderBlob *compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, UINT optimizationFlags, bool alternateFlags);
-
     egl::Display *mDisplay;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(Renderer);
 
-    HMODULE mD3dCompilerModule;
-    pCompileFunc mD3DCompileFunc;
     int mCurrentClientVersion;
 };
 
diff --git a/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
new file mode 100644
index 0000000..f45ba5b
--- /dev/null
+++ b/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
@@ -0,0 +1,163 @@
+#include "precompiled.h"
+#include "libGLESv2/renderer/d3d/HLSLCompiler.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/main.h"
+
+#include "common/utilities.h"
+
+#include "third_party/trace_event/trace_event.h"
+
+namespace rx
+{
+
+HLSLCompiler::HLSLCompiler()
+    : mD3DCompilerModule(NULL),
+      mD3DCompileFunc(NULL)
+{
+}
+
+HLSLCompiler::~HLSLCompiler()
+{
+    release();
+}
+
+bool HLSLCompiler::initialize()
+{
+    TRACE_EVENT0("gpu", "initializeCompiler");
+#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES)
+    // Find a D3DCompiler module that had already been loaded based on a predefined list of versions.
+    static TCHAR* d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES;
+
+    for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i)
+    {
+        if (GetModuleHandleEx(0, d3dCompilerNames[i], &mD3DCompilerModule))
+        {
+            break;
+        }
+    }
+#endif  // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES
+
+    if (!mD3DCompilerModule)
+    {
+        // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with.
+        mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL);
+    }
+
+    if (!mD3DCompilerModule)
+    {
+        ERR("No D3D compiler module found - aborting!\n");
+        return false;
+    }
+
+    mD3DCompileFunc = reinterpret_cast<CompileFuncPtr>(GetProcAddress(mD3DCompilerModule, "D3DCompile"));
+    ASSERT(mD3DCompileFunc);
+
+    return mD3DCompileFunc != NULL;
+}
+
+void HLSLCompiler::release()
+{
+    if (mD3DCompilerModule)
+    {
+        FreeLibrary(mD3DCompilerModule);
+        mD3DCompilerModule = NULL;
+        mD3DCompileFunc = NULL;
+    }
+}
+
+ShaderBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile,
+                                         unsigned int optimizationFlags, bool alternateFlags) const
+{
+    ASSERT(mD3DCompilerModule && mD3DCompileFunc);
+
+    if (!hlsl)
+    {
+        return NULL;
+    }
+
+    HRESULT result = S_OK;
+    UINT flags = 0;
+    std::string sourceText;
+    if (gl::perfActive())
+    {
+        flags |= D3DCOMPILE_DEBUG;
+
+#ifdef NDEBUG
+        flags |= optimizationFlags;
+#else
+        flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
+#endif
+
+        std::string sourcePath = getTempPath();
+        sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
+        writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
+    }
+    else
+    {
+        flags |= optimizationFlags;
+        sourceText = hlsl;
+    }
+
+    // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
+    // Try the default flags first and if compilation fails, try some alternatives.
+    const static UINT extraFlags[] =
+    {
+        0,
+        D3DCOMPILE_AVOID_FLOW_CONTROL,
+        D3DCOMPILE_PREFER_FLOW_CONTROL
+    };
+
+    const static char * const extraFlagNames[] =
+    {
+        "default",
+        "avoid flow control",
+        "prefer flow control"
+    };
+
+    int attempts = alternateFlags ? ArraySize(extraFlags) : 1;
+    pD3DCompile compileFunc = reinterpret_cast<pD3DCompile>(mD3DCompileFunc);
+    for (int i = 0; i < attempts; ++i)
+    {
+        ID3DBlob *errorMessage = NULL;
+        ID3DBlob *binary = NULL;
+
+        result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL,
+            "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage);
+        if (errorMessage)
+        {
+            const char *message = (const char*)errorMessage->GetBufferPointer();
+
+            infoLog.appendSanitized(message);
+            TRACE("\n%s", hlsl);
+            TRACE("\n%s", message);
+
+            SafeRelease(errorMessage);
+        }
+
+        if (SUCCEEDED(result))
+        {
+            return (ShaderBlob*)binary;
+        }
+        else
+        {
+            if (result == E_OUTOFMEMORY)
+            {
+                return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*)NULL);
+            }
+
+            infoLog.append("Warning: D3D shader compilation failed with ");
+            infoLog.append(extraFlagNames[i]);
+            infoLog.append(" flags.");
+            if (i + 1 < attempts)
+            {
+                infoLog.append(" Retrying with ");
+                infoLog.append(extraFlagNames[i + 1]);
+                infoLog.append(".\n");
+            }
+        }
+    }
+
+    return NULL;
+}
+
+}
diff --git a/src/libGLESv2/renderer/d3d/HLSLCompiler.h b/src/libGLESv2/renderer/d3d/HLSLCompiler.h
new file mode 100644
index 0000000..cf8caf2
--- /dev/null
+++ b/src/libGLESv2/renderer/d3d/HLSLCompiler.h
@@ -0,0 +1,40 @@
+#ifndef LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_
+#define LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_
+
+#include "common/angleutils.h"
+
+#include <windows.h>
+
+namespace gl
+{
+class InfoLog;
+}
+
+namespace rx
+{
+
+typedef void* ShaderBlob;
+typedef void(*CompileFuncPtr)();
+
+class HLSLCompiler
+{
+  public:
+    HLSLCompiler();
+    ~HLSLCompiler();
+
+    bool initialize();
+    void release();
+
+    ShaderBlob *compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile,
+                                unsigned int optimizationFlags, bool alternateFlags) const;
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(HLSLCompiler);
+
+    HMODULE mD3DCompilerModule;
+    CompileFuncPtr mD3DCompileFunc;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
index 31d31c4..f9c84dd 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
@@ -113,7 +113,7 @@
 
 EGLint Renderer11::initialize()
 {
-    if (!initializeCompiler())
+    if (!mCompiler.initialize())
     {
         return EGL_NOT_INITIALIZED;
     }
@@ -1800,6 +1800,8 @@
         FreeLibrary(mDxgiModule);
         mDxgiModule = NULL;
     }
+
+    mCompiler.release();
 }
 
 bool Renderer11::resetDevice()
@@ -2837,7 +2839,7 @@
         return NULL;
     }
 
-    ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, D3DCOMPILE_OPTIMIZATION_LEVEL0, false);
+    ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, D3DCOMPILE_OPTIMIZATION_LEVEL0, false);
     if (!binary)
     {
         return NULL;
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.h b/src/libGLESv2/renderer/d3d11/Renderer11.h
index 2f7d403..1a1ea0e 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.h
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.h
@@ -14,6 +14,7 @@
 #include "common/mathutil.h"
 
 #include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/renderer/d3d/HLSLCompiler.h"
 #include "libGLESv2/renderer/d3d11/RenderStateCache.h"
 #include "libGLESv2/renderer/d3d11/InputLayoutCache.h"
 #include "libGLESv2/renderer/RenderTarget.h"
@@ -250,6 +251,8 @@
     HMODULE mDxgiModule;
     HDC mDc;
 
+    HLSLCompiler mCompiler;
+
     bool mDeviceLost;
 
     void initializeDevice();
diff --git a/src/libGLESv2/renderer/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d9/Renderer9.cpp
index 2e7c083..7aae33b 100644
--- a/src/libGLESv2/renderer/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d9/Renderer9.cpp
@@ -156,6 +156,8 @@
     SafeRelease(mD3d9);
     SafeRelease(mD3d9Ex);
 
+    mCompiler.release();
+
     if (mDeviceWindow)
     {
         DestroyWindow(mDeviceWindow);
@@ -173,7 +175,7 @@
 
 EGLint Renderer9::initialize()
 {
-    if (!initializeCompiler())
+    if (!mCompiler.initialize())
     {
         return EGL_NOT_INITIALIZED;
     }
@@ -3348,7 +3350,7 @@
     // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization
     UINT optimizationFlags = (workaround == ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER ? D3DCOMPILE_SKIP_OPTIMIZATION : ANGLE_COMPILE_OPTIMIZATION_LEVEL);
 
-    ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, optimizationFlags, true);
+    ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, optimizationFlags, true);
     if (!binary)
     {
         return NULL;
diff --git a/src/libGLESv2/renderer/d3d9/Renderer9.h b/src/libGLESv2/renderer/d3d9/Renderer9.h
index 78e70cc..f568cb1 100644
--- a/src/libGLESv2/renderer/d3d9/Renderer9.h
+++ b/src/libGLESv2/renderer/d3d9/Renderer9.h
@@ -11,6 +11,7 @@
 
 #include "common/angleutils.h"
 #include "common/mathutil.h"
+#include "libGLESv2/renderer/d3d/HLSLCompiler.h"
 #include "libGLESv2/renderer/d3d9/ShaderCache.h"
 #include "libGLESv2/renderer/d3d9/VertexDeclarationCache.h"
 #include "libGLESv2/renderer/Renderer.h"
@@ -261,6 +262,8 @@
     IDirect3DDevice9 *mDevice;
     IDirect3DDevice9Ex *mDeviceEx;  // Might be null if D3D9Ex is not supported.
 
+    HLSLCompiler mCompiler;
+
     Blit9 *mBlit;
 
     HWND mDeviceWindow;