Commit 3cfd7225 by apatrick@chromium.org

Cache D3D vertex and pixel shader objects so they can be reused and shared by multiple contexts.

WebGL conformance tests did not regress. I verified they exercise the Blit code. Review URL: https://codereview.appspot.com/6345105 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1225 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent e640ef8e
...@@ -294,6 +294,9 @@ bool Display::initialize() ...@@ -294,6 +294,9 @@ bool Display::initialize()
return false; return false;
} }
mVertexShaderCache.initialize(mDevice);
mPixelShaderCache.initialize(mDevice);
return true; return true;
} }
...@@ -315,6 +318,9 @@ void Display::terminate() ...@@ -315,6 +318,9 @@ void Display::terminate()
mEventQueryPool.pop_back(); mEventQueryPool.pop_back();
} }
mVertexShaderCache.clear();
mPixelShaderCache.clear();
if (mDevice) if (mDevice)
{ {
// If the device is lost, reset it first to prevent leaving the driver in an unstable state // If the device is lost, reset it first to prevent leaving the driver in an unstable state
...@@ -751,6 +757,9 @@ bool Display::restoreLostDevice() ...@@ -751,6 +757,9 @@ bool Display::restoreLostDevice()
mEventQueryPool.pop_back(); mEventQueryPool.pop_back();
} }
mVertexShaderCache.clear();
mPixelShaderCache.clear();
if (!resetDevice()) if (!resetDevice())
{ {
return false; return false;
...@@ -1216,6 +1225,16 @@ bool Display::shareHandleSupported() const ...@@ -1216,6 +1225,16 @@ bool Display::shareHandleSupported() const
return isD3d9ExDevice() && !gl::perfActive(); return isD3d9ExDevice() && !gl::perfActive();
} }
IDirect3DVertexShader9 *Display::createVertexShader(const DWORD *function, size_t length)
{
return mVertexShaderCache.create(function, length);
}
IDirect3DPixelShader9 *Display::createPixelShader(const DWORD *function, size_t length)
{
return mPixelShaderCache.create(function, length);
}
// Only Direct3D 10 ready devices support all the necessary vertex texture formats. // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
// We test this using D3D9 by checking support for the R16F format. // We test this using D3D9 by checking support for the R16F format.
bool Display::getVertexTextureSupport() const bool Display::getVertexTextureSupport() const
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
// display on which graphics are drawn. Implements EGLDisplay. // display on which graphics are drawn. Implements EGLDisplay.
// [EGL 1.4] section 2.1.2 page 3. // [EGL 1.4] section 2.1.2 page 3.
#ifndef INCLUDE_DISPLAY_H_ #ifndef LIBEGL_DISPLAY_H_
#define INCLUDE_DISPLAY_H_ #define LIBEGL_DISPLAY_H_
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "libGLESv2/Context.h" #include "libGLESv2/Context.h"
#include "libEGL/Config.h" #include "libEGL/Config.h"
#include "libEGL/ShaderCache.h"
#include "libEGL/Surface.h" #include "libEGL/Surface.h"
namespace egl namespace egl
...@@ -92,6 +93,9 @@ class Display ...@@ -92,6 +93,9 @@ class Display
const char *getExtensionString() const; const char *getExtensionString() const;
bool shareHandleSupported() const; bool shareHandleSupported() const;
virtual IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length);
virtual IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length);
private: private:
DISALLOW_COPY_AND_ASSIGN(Display); DISALLOW_COPY_AND_ASSIGN(Display);
...@@ -116,6 +120,9 @@ class Display ...@@ -116,6 +120,9 @@ class Display
// A pool of event queries that are currently unused. // A pool of event queries that are currently unused.
std::vector<IDirect3DQuery9*> mEventQueryPool; std::vector<IDirect3DQuery9*> mEventQueryPool;
VertexShaderCache mVertexShaderCache;
PixelShaderCache mPixelShaderCache;
D3DCAPS9 mDeviceCaps; D3DCAPS9 mDeviceCaps;
D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; D3DADAPTER_IDENTIFIER9 mAdapterIdentifier;
HWND mDeviceWindow; HWND mDeviceWindow;
...@@ -143,4 +150,4 @@ class Display ...@@ -143,4 +150,4 @@ class Display
}; };
} }
#endif // INCLUDE_DISPLAY_H_ #endif // LIBEGL_DISPLAY_H_
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Display.h: Defines egl::ShaderCache, a cache of Direct3D shader objects
// keyed by their byte code.
#ifndef LIBEGL_SHADER_CACHE_H_
#define LIBEGL_SHADER_CACHE_H_
#include <d3d9.h>
#include <hash_map>
namespace egl
{
template <typename ShaderObject>
class ShaderCache
{
public:
ShaderCache() : mDevice(NULL)
{
}
~ShaderCache()
{
// Call clear while the device is still valid.
ASSERT(mMap.empty());
}
void initialize(IDirect3DDevice9* device)
{
mDevice = device;
}
ShaderObject *create(const DWORD *function, size_t length)
{
std::string key(reinterpret_cast<const char*>(function), length);
Map::iterator it = mMap.find(key);
if (it != mMap.end())
{
it->second->AddRef();
return it->second;
}
ShaderObject *shader;
HRESULT result = createShader(function, &shader);
if (FAILED(result))
{
return NULL;
}
// Random eviction policy.
if (mMap.size() >= kMaxMapSize)
{
mMap.begin()->second->Release();
mMap.erase(mMap.begin());
}
shader->AddRef();
mMap[key] = shader;
return shader;
}
void clear()
{
for (Map::iterator it = mMap.begin(); it != mMap.end(); ++it)
{
it->second->Release();
}
mMap.clear();
}
private:
DISALLOW_COPY_AND_ASSIGN(ShaderCache);
const static size_t kMaxMapSize = 100;
HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader)
{
return mDevice->CreateVertexShader(function, shader);
}
HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader)
{
return mDevice->CreatePixelShader(function, shader);
}
typedef stdext::hash_map<std::string, ShaderObject*> Map;
Map mMap;
IDirect3DDevice9 *mDevice;
};
typedef ShaderCache<IDirect3DVertexShader9> VertexShaderCache;
typedef ShaderCache<IDirect3DPixelShader9> PixelShaderCache;
}
#endif // LIBEGL_SHADER_CACHE_H_
...@@ -192,10 +192,11 @@ void Blit::initGeometry() ...@@ -192,10 +192,11 @@ void Blit::initGeometry()
template <class D3DShaderType> template <class D3DShaderType>
bool Blit::setShader(ShaderId source, const char *profile, bool Blit::setShader(ShaderId source, const char *profile,
HRESULT (WINAPI IDirect3DDevice9::*createShader)(const DWORD *, D3DShaderType**), D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length),
HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
{ {
IDirect3DDevice9 *device = getDevice(); egl::Display *display = getDisplay();
IDirect3DDevice9 *device = display->getDevice();
D3DShaderType *shader; D3DShaderType *shader;
...@@ -205,6 +206,7 @@ bool Blit::setShader(ShaderId source, const char *profile, ...@@ -205,6 +206,7 @@ bool Blit::setShader(ShaderId source, const char *profile,
} }
else else
{ {
// FIXME: Complile these shaders offline and embed the byte code in the module.
ID3DXBuffer *shaderCode; ID3DXBuffer *shaderCode;
HRESULT hr = D3DXCompileShader(mShaderSource[source], strlen(mShaderSource[source]), NULL, NULL, "main", profile, 0, &shaderCode, NULL, NULL); HRESULT hr = D3DXCompileShader(mShaderSource[source], strlen(mShaderSource[source]), NULL, NULL, "main", profile, 0, &shaderCode, NULL, NULL);
...@@ -214,7 +216,7 @@ bool Blit::setShader(ShaderId source, const char *profile, ...@@ -214,7 +216,7 @@ bool Blit::setShader(ShaderId source, const char *profile,
return false; return false;
} }
hr = (device->*createShader)(static_cast<const DWORD*>(shaderCode->GetBufferPointer()), &shader); shader = (display->*createShader)(static_cast<const DWORD*>(shaderCode->GetBufferPointer()), shaderCode->GetBufferSize());
if (FAILED(hr)) if (FAILED(hr))
{ {
shaderCode->Release(); shaderCode->Release();
...@@ -240,12 +242,12 @@ bool Blit::setShader(ShaderId source, const char *profile, ...@@ -240,12 +242,12 @@ bool Blit::setShader(ShaderId source, const char *profile,
bool Blit::setVertexShader(ShaderId shader) bool Blit::setVertexShader(ShaderId shader)
{ {
return setShader<IDirect3DVertexShader9>(shader, mContext->supportsShaderModel3() ? "vs_3_0" : "vs_2_0", &IDirect3DDevice9::CreateVertexShader, &IDirect3DDevice9::SetVertexShader); return setShader<IDirect3DVertexShader9>(shader, mContext->supportsShaderModel3() ? "vs_3_0" : "vs_2_0", &egl::Display::createVertexShader, &IDirect3DDevice9::SetVertexShader);
} }
bool Blit::setPixelShader(ShaderId shader) bool Blit::setPixelShader(ShaderId shader)
{ {
return setShader<IDirect3DPixelShader9>(shader, mContext->supportsShaderModel3() ? "ps_3_0" : "ps_2_0", &IDirect3DDevice9::CreatePixelShader, &IDirect3DDevice9::SetPixelShader); return setShader<IDirect3DPixelShader9>(shader, mContext->supportsShaderModel3() ? "ps_3_0" : "ps_2_0", &egl::Display::createPixelShader, &IDirect3DDevice9::SetPixelShader);
} }
RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libEGL/Display.h"
namespace gl namespace gl
{ {
class Context; class Context;
...@@ -74,7 +76,7 @@ class Blit ...@@ -74,7 +76,7 @@ class Blit
template <class D3DShaderType> template <class D3DShaderType>
bool setShader(ShaderId source, const char *profile, bool setShader(ShaderId source, const char *profile,
HRESULT (WINAPI IDirect3DDevice9::*createShader)(const DWORD *, D3DShaderType **), D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length),
HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*));
bool setVertexShader(ShaderId shader); bool setVertexShader(ShaderId shader);
......
...@@ -1717,15 +1717,15 @@ bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) ...@@ -1717,15 +1717,15 @@ bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
const char *vertexShaderFunction = ptr; const char *vertexShaderFunction = ptr;
ptr += vertexShaderSize; ptr += vertexShaderSize;
HRESULT result = mDevice->CreatePixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), &mPixelExecutable); mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
if (FAILED(result)) if (!mPixelExecutable)
{ {
infoLog.append("Could not create pixel shader."); infoLog.append("Could not create pixel shader.");
return false; return false;
} }
result = mDevice->CreateVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), &mVertexExecutable); mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
if (FAILED(result)) if (!mVertexExecutable)
{ {
infoLog.append("Could not create vertex shader."); infoLog.append("Could not create vertex shader.");
mPixelExecutable->Release(); mPixelExecutable->Release();
...@@ -1897,51 +1897,52 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin ...@@ -1897,51 +1897,52 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin
if (vertexBinary && pixelBinary) if (vertexBinary && pixelBinary)
{ {
HRESULT vertexResult = mDevice->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable); mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
HRESULT pixelResult = mDevice->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable); if (!mVertexExecutable)
if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
{ {
return error(GL_OUT_OF_MEMORY, false); return error(GL_OUT_OF_MEMORY, false);
} }
ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult)); mPixelExecutable = getDisplay()->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize());
if (!mPixelExecutable)
{
mVertexExecutable->Release();
mVertexExecutable = NULL;
return error(GL_OUT_OF_MEMORY, false);
}
vertexBinary->Release(); vertexBinary->Release();
pixelBinary->Release(); pixelBinary->Release();
vertexBinary = NULL; vertexBinary = NULL;
pixelBinary = NULL; pixelBinary = NULL;
if (mVertexExecutable && mPixelExecutable) if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
{ {
if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader)) return false;
{ }
return false;
}
if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS)) if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
{ {
return false; return false;
} }
if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS)) if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
{ {
return false; return false;
} }
// these uniforms are searched as already-decorated because gl_ and dx_ // these uniforms are searched as already-decorated because gl_ and dx_
// are reserved prefixes, and do not receive additional decoration // are reserved prefixes, and do not receive additional decoration
mDxDepthRangeLocation = getUniformLocation("dx_DepthRange"); mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
mDxDepthLocation = getUniformLocation("dx_Depth"); mDxDepthLocation = getUniformLocation("dx_Depth");
mDxCoordLocation = getUniformLocation("dx_Coord"); mDxCoordLocation = getUniformLocation("dx_Coord");
mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize"); mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW"); mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines"); mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
context->markDxUniformsDirty(); context->markDxUniformsDirty();
return true; return true;
}
} }
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment