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()
return false;
}
mVertexShaderCache.initialize(mDevice);
mPixelShaderCache.initialize(mDevice);
return true;
}
......@@ -315,6 +318,9 @@ void Display::terminate()
mEventQueryPool.pop_back();
}
mVertexShaderCache.clear();
mPixelShaderCache.clear();
if (mDevice)
{
// If the device is lost, reset it first to prevent leaving the driver in an unstable state
......@@ -751,6 +757,9 @@ bool Display::restoreLostDevice()
mEventQueryPool.pop_back();
}
mVertexShaderCache.clear();
mPixelShaderCache.clear();
if (!resetDevice())
{
return false;
......@@ -1216,6 +1225,16 @@ bool Display::shareHandleSupported() const
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.
// We test this using D3D9 by checking support for the R16F format.
bool Display::getVertexTextureSupport() const
......
......@@ -8,8 +8,8 @@
// display on which graphics are drawn. Implements EGLDisplay.
// [EGL 1.4] section 2.1.2 page 3.
#ifndef INCLUDE_DISPLAY_H_
#define INCLUDE_DISPLAY_H_
#ifndef LIBEGL_DISPLAY_H_
#define LIBEGL_DISPLAY_H_
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
......@@ -23,6 +23,7 @@
#include "libGLESv2/Context.h"
#include "libEGL/Config.h"
#include "libEGL/ShaderCache.h"
#include "libEGL/Surface.h"
namespace egl
......@@ -92,6 +93,9 @@ class Display
const char *getExtensionString() const;
bool shareHandleSupported() const;
virtual IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length);
virtual IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length);
private:
DISALLOW_COPY_AND_ASSIGN(Display);
......@@ -116,6 +120,9 @@ class Display
// A pool of event queries that are currently unused.
std::vector<IDirect3DQuery9*> mEventQueryPool;
VertexShaderCache mVertexShaderCache;
PixelShaderCache mPixelShaderCache;
D3DCAPS9 mDeviceCaps;
D3DADAPTER_IDENTIFIER9 mAdapterIdentifier;
HWND mDeviceWindow;
......@@ -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()
template <class D3DShaderType>
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*))
{
IDirect3DDevice9 *device = getDevice();
egl::Display *display = getDisplay();
IDirect3DDevice9 *device = display->getDevice();
D3DShaderType *shader;
......@@ -205,6 +206,7 @@ bool Blit::setShader(ShaderId source, const char *profile,
}
else
{
// FIXME: Complile these shaders offline and embed the byte code in the module.
ID3DXBuffer *shaderCode;
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,
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))
{
shaderCode->Release();
......@@ -240,12 +242,12 @@ bool Blit::setShader(ShaderId source, const char *profile,
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)
{
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
......
......@@ -18,6 +18,8 @@
#include "common/angleutils.h"
#include "libEGL/Display.h"
namespace gl
{
class Context;
......@@ -74,7 +76,7 @@ class Blit
template <class D3DShaderType>
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*));
bool setVertexShader(ShaderId shader);
......
......@@ -1717,15 +1717,15 @@ bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
const char *vertexShaderFunction = ptr;
ptr += vertexShaderSize;
HRESULT result = mDevice->CreatePixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), &mPixelExecutable);
if (FAILED(result))
mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), pixelShaderSize);
if (!mPixelExecutable)
{
infoLog.append("Could not create pixel shader.");
return false;
}
result = mDevice->CreateVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), &mVertexExecutable);
if (FAILED(result))
mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), vertexShaderSize);
if (!mVertexExecutable)
{
infoLog.append("Could not create vertex shader.");
mPixelExecutable->Release();
......@@ -1897,51 +1897,52 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin
if (vertexBinary && pixelBinary)
{
HRESULT vertexResult = mDevice->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
HRESULT pixelResult = mDevice->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize());
if (!mVertexExecutable)
{
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();
pixelBinary->Release();
vertexBinary = 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))
{
return false;
}
if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
{
return false;
}
if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
{
return false;
}
if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
{
return false;
}
// these uniforms are searched as already-decorated because gl_ and dx_
// are reserved prefixes, and do not receive additional decoration
mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
mDxDepthLocation = getUniformLocation("dx_Depth");
mDxCoordLocation = getUniformLocation("dx_Coord");
mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
// these uniforms are searched as already-decorated because gl_ and dx_
// are reserved prefixes, and do not receive additional decoration
mDxDepthRangeLocation = getUniformLocation("dx_DepthRange");
mDxDepthLocation = getUniformLocation("dx_Depth");
mDxCoordLocation = getUniformLocation("dx_Coord");
mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize");
mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW");
mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines");
context->markDxUniformsDirty();
context->markDxUniformsDirty();
return true;
}
return true;
}
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