既存の D3D アプリケーションのレンダリング結果に、 自前のポスト処理/オーバーレイを付加したり、スクリーンショット撮ったりする (FXAA とかああいう) のはどーやってるの?
逆順に説明すると、以下のようになる:
- →
IDirect3DDevice9::EndScene()
やIDirect3DSwapChain9::Present()
をフックして、レンダリングが終わった後に加工を行う - →
Direct3DCreate9()
を実行した際に、COM インターフェースの Vtbl を書き換えて、EndScene()
等をフックする - → ニセの d3d9.dll (プロキシDLL) を使って、
Direct3DCreate9
をフックする
ターゲットとなる実行ファイルがあるディレクトリに、プロキシ DLL (自前で用意したニセの d3d9.dll) を配置する。
通常の DLL 検索ルール の場合、ターゲットの存在するディレクトリから DLL を探した後、 システムディレクトリの DLL を見に行くので、 ターゲットと同一ディレクトリの d3d9.dll が先に読み込まれる。
プロキシ DLL からは、本物の %SystemRoot%\System32\d3d9.dll
内の関数を呼び出す。
%SystemRoot%\System32
は GetSystemDirectory()
を用いて取得する。
最小限の、プロキシ DLL の実験
- 下記のコードをコンパイル
- 出力された実行ファイルを d3d9.dll にリネーム
- リネームした d3d9.dll をターゲットの実行ファイルと同じディレクトリに配置
- DebugView を実行
- ターゲットの実行ファイルを起動
- DebugView のウィンドウに
OutputDebugString()
内のメッセージ ("My Injection Test : Direct3DCreate9"
) が出る
ターゲットによっては出ないかも。全然ダメな場合は D3D9 のチュートリアル等で試すこと。
#define _CRT_SECURE_NO_WARNINGS
#include <d3d9.h>
#include <tchar.h>
#pragma comment(linker, "/DLL")
static IDirect3D9* (WINAPI *o_Direct3DCreate9)(UINT);
IDirect3D9* WINAPI Direct3DCreate9(UINT SDKVersion) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
OutputDebugString(_T("My Injection Test : Direct3DCreate9\n"));
IDirect3D9 *iDirect3D9 = o_Direct3DCreate9(SDKVersion);
return iDirect3D9;
}
BOOL APIENTRY DllMain(HINSTANCE, DWORD fdwReason, LPVOID) {
if(fdwReason == DLL_PROCESS_ATTACH) {
TCHAR fn[MAX_PATH];
UINT l = GetSystemDirectory(fn, _countof(fn));
_tcscpy(fn + l, _T("\\d3d9.dll"));
HMODULE hModule = LoadLibrary(fn);
* (void**) &o_Direct3DCreate9 = GetProcAddress(hModule, "Direct3DCreate9");
}
return TRUE;
}
以下、C++ コードから CINTERFACE
を使うので、d3dx9core.h の記述ミスを修正する。
d3dx9core.h の中で
DECLARE_INTERFACE_(ID3DXFont, IUnknown)
{
...
#ifdef __cplusplus
となっているものを
DECLARE_INTERFACE_(ID3DXFont, IUnknown)
{
...
#if defined(__cplusplus) && !defined(CINTERFACE)
と修正する。
Direct3DCreate9()
が返す IDirect3D9
の Vtbl を加工することで、IDirect3D9::CreateDevice()
をフックする。
d3d9.h を #include する前に、シンボル CINTERFACE
を定義しておくと、COM のインターフェースがより扱いやすい形で見えるようになる。
具体的には、以下のような定義が行われる
struct IDirect3D {
struct IDirect3DVtbl* lpVtbl;
};
struct IDirect3DVtbl {
HRESULT (STDMETHODCALLTYPE* QueryInterface)(...);
...
};
ここで、IDirect3D::lpVtbl
が指す構造体 IDirect3DVtbl
がターゲットの Vtbl となる。
CINTERFACE
定義済みのまま d3d9.h を用いても良いが、通常の C++ インターフェースが使えずに冗長になるので、
下記のコードでは細工を行っている。
細工の結果として、namespace MyInterface
の場合は CINTERFACE
版の IDirect3D
にアクセスできるようになる。
あとは MyInterface::IDirect3D::lpVtbl
が指す Vtbl を書き換えれば良い。
ただし、このメモリ領域は保護指定が PAGE_EXECUTE_READ
(0x0020) になっているので、
まず書き換え可能 PAGE_EXECUTE_WRITECOPY
(0x0080) に変更し、書き換え後、元に戻す必要がある。
以下のサンプルを前述のサンプル同様に実行すると、
フックの結果として DebugView にメッセージ ("My Injection Test : IDirect3D9::CreateDevice - SUCCEEDED"
) が出る。
#define _CRT_SECURE_NO_WARNINGS
#include <d3d9.h>
#include <tchar.h>
#pragma comment(linker, "/DLL")
namespace MyInterface {
#pragma warning(push)
#define CINTERFACE // Windows SDK : BaseTypes.h
#pragma warning(disable : 4005)
#define STDMETHOD_(type,method) type (STDMETHODCALLTYPE * method)
#define STDMETHOD(method) STDMETHOD_(HRESULT,method)
#define PURE
#define THIS INTERFACE FAR* This
#define THIS_ THIS,
#define DECLARE_INTERFACE(iface) typedef interface iface { struct iface##Vtbl FAR* lpVtbl; } iface; \
typedef struct iface##Vtbl iface##Vtbl; struct iface##Vtbl
#define DECLARE_INTERFACE_(iface,b) DECLARE_INTERFACE(iface)
#undef _D3D9_H_
#include <d3d9.h>
#pragma warning(pop)
} // namespace MyInterface
static IDirect3D9* (WINAPI *o_Direct3DCreate9)(UINT);
static HRESULT (WINAPI *o_IDirect3D9_CreateDevice)(IDirect3D9*, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS*, IDirect3DDevice9**);
static HRESULT WINAPI my_IDirect3D9_CreateDevice(IDirect3D9* direct3d, UINT adapter, D3DDEVTYPE type, HWND window, DWORD flag, D3DPRESENT_PARAMETERS* param, IDirect3DDevice9** ppDevice) {
HRESULT hr = o_IDirect3D9_CreateDevice(direct3d, adapter, type, window, flag, param, ppDevice);
if(SUCCEEDED(hr)) {
OutputDebugString(_T("My Injection Test : IDirect3D9::CreateDevice - SUCCEEDED\n"));
}
return hr;
}
IDirect3D9* WINAPI Direct3DCreate9(UINT SDKVersion) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
IDirect3D9 *iDirect3D9 = o_Direct3DCreate9(SDKVersion);
if(iDirect3D9) {
OutputDebugString(_T("My Injection Test : d3d9.dll::Direct3DCreate9 - SUCCEEDED\n"));
MyInterface::IDirect3D9Vtbl* p = ((MyInterface::IDirect3D9*) iDirect3D9)->lpVtbl;
DWORD protect = PAGE_EXECUTE_WRITECOPY;
VirtualProtect(p, sizeof(*p), protect, &protect);
* (void**) &o_IDirect3D9_CreateDevice = (void*) p->CreateDevice;
* (void**) &p->CreateDevice = (void*) my_IDirect3D9_CreateDevice;
VirtualProtect(p, sizeof(*p), protect, &protect);
}
return iDirect3D9;
}
BOOL APIENTRY DllMain(HINSTANCE, DWORD fdwReason, LPVOID) {
if(fdwReason == DLL_PROCESS_ATTACH) {
TCHAR fn[MAX_PATH];
_tcscpy(fn + GetSystemDirectory(fn, _countof(fn)), _T("\\d3d9.dll"));
HMODULE hModule = LoadLibrary(fn);
* (void**) &o_Direct3DCreate9 = GetProcAddress(hModule, "Direct3DCreate9");
}
return TRUE;
}
ここでは IDirect3DDevice9
の以下のメソッドをフックすることで、加工処理を行う
IDirect3DDevice9::BeginStateBlock
IDirect3DDevice9::EndStateBlock
IDirect3DDevice9::Reset
IDirect3DDevice9::Present
このうち、実際の描画処理を行うのは IDirect3DDevice9::Present
のみで、他のメソッドはフックおよび状態の整合性の維持に用いる。
IDirect3DDevice9::BeginStateBlock
および IDirect3DDevice9::EndStateBlock
は IDirect3DDevice9
の Vtbl を書き換える
ので、それぞれの処理後に、Vtbl の値を元に戻す処理を行う。
IDirect3DDevice9::Reset
の実行時にはリソースの開放が必要なので、
実際の処理を行う前に、加工用のリソースの開放を行う。
IDirect3DDevice9::Present
の実行前に、以下の流れで、加工処理を行う。
IDirect3DDevice9::GetBackBuffer
を用いてバックバッファを取得するD3DXCreateEffectFromFile
を用いて、エフェクトを生成する- バックバッファとマッチするテクスチャ/レンダーターゲットを生成する
- 上記の要素を用いてポスト処理を行う
ポスト処理そのものについては割愛。
アプリケーションによっては、Direct3DCreate9
以外の関数も LoadLibrary()
しているものがあるので、
本物の d3d9.dll 相当の関数をエクスポートする。
VisualC++2010 がインストールされている環境であれば、以下のようなコマンドラインで、 実際の d3d9.dll が持つ関数を知ることができる
call "%VS100COMNTOOLS%..\..\VC\bin\vcvars32.bat"
dumpbin /EXPORTS %SystemRoot%\System32\d3d9.dll
結果は以下のようになる
ordinal hint RVA name
4 0 00086E18 D3DPERF_BeginEvent
5 1 00086E70 D3DPERF_EndEvent
6 2 00086FF8 D3DPERF_GetStatus
7 3 00086F60 D3DPERF_QueryRepeatFrame
8 4 00086EC0 D3DPERF_SetMarker
9 5 00086FAC D3DPERF_SetOptions
10 6 00086F10 D3DPERF_SetRegion
11 7 00087E20 DebugSetLevel
12 8 0001B800 DebugSetMute
13 9 000396B0 Direct3DCreate9
14 A 00002460 Direct3DCreate9Ex
1 B 0001DCDC Direct3DShaderValidatorCreate9
2 C 000821A8 PSGPError
3 D 000820F4 PSGPSampleTexture
それぞれ適切な、何もしないフックを行う。以下は D3DPERF_SetMarker()
の例
static void (WINAPI *o_D3DPERF_SetMarker)(D3DCOLOR, LPCWSTR);
void WINAPI D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_SetMarker(col, wszName);
}
BOOL APIENTRY DllMain(HINSTANCE, DWORD fdwReason, LPVOID) {
if(fdwReason == DLL_PROCESS_ATTACH) {
...
* (void**) &o_D3DPERF_SetMarker = GetProcAddress(h, "D3DPERF_SetMarker");
}
}
- effect.fx ファイルはプロキシDLLと同じディレクトリに置くこと
- 実行に成功すると pass1 で r=1.0, pass2 で b=0.0 を書き込み、結果として画面が赤~黄色っぽくなる
#define _CRT_SECURE_NO_WARNINGS
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#pragma comment(linker, "/DLL")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dxguid.lib")
namespace MyInterface {
#pragma warning(push)
#define CINTERFACE // Windows SDK : BaseTypes.h
#pragma warning(disable : 4005)
#define STDMETHOD_(type,method) type (STDMETHODCALLTYPE * method)
#define STDMETHOD(method) STDMETHOD_(HRESULT,method)
#define PURE
#define THIS INTERFACE FAR* This
#define THIS_ THIS,
#define DECLARE_INTERFACE(iface) typedef interface iface { struct iface##Vtbl FAR* lpVtbl; } iface; \
typedef struct iface##Vtbl iface##Vtbl; struct iface##Vtbl
#define DECLARE_INTERFACE_(iface,b) DECLARE_INTERFACE(iface)
#undef _D3D9_H_
#include <d3d9.h>
#pragma warning(pop)
} // namespace MyInterface
class Effect {
protected:
Effect(IDirect3DDevice9* device) : pEffect(0), maxPass(2) {
memset(image, 0, sizeof(image));
}
~Effect() {
clear();
}
template<typename T> static void safeRelease(T*& p) {
if(p) {
p->Release();
p = 0;
}
}
void clear() {
for(int i = 0; i < _countof(image); ++i) {
image[i].release();
}
safeRelease(pEffect);
}
void draw(IDirect3DDevice9* d) {
IDirect3DSurface9* pBackBuffer = 0;
D3DSURFACE_DESC bbd = { (D3DFORMAT) 0 };
if(SUCCEEDED(d->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) {
pBackBuffer->GetDesc(&bbd);
}
if(! pEffect) {
TCHAR mfn[MAX_PATH+1], drive[MAX_PATH+1], dir[MAX_PATH+1], srcFile[MAX_PATH+1];
GetModuleFileName(0, mfn, _countof(mfn));
_tsplitpath_s(mfn, drive, _countof(drive), dir, _countof(dir), 0, 0, 0, 0);
wsprintf(srcFile, _T("%s%s%s"), drive, dir, _T("effect.fx"));
clear();
D3DXCreateEffectFromFile(d, srcFile, 0, 0, D3DXFX_NOT_CLONEABLE, 0, &pEffect, 0);
}
if(pBackBuffer && pEffect) {
for(int pass = 0; pass < maxPass; ++pass) {
Image& m = image[pass];
if(m.desc.Width != bbd.Width || m.desc.Height != bbd.Height || m.desc.Format != bbd.Format) {
m.release();
}
if(! m.texture) {
if(SUCCEEDED(d->CreateTexture(bbd.Width, bbd.Height, 1, D3DUSAGE_RENDERTARGET, bbd.Format, D3DPOOL_DEFAULT, &m.texture, 0))) {
m.desc = bbd;
m.texture->GetSurfaceLevel(0, &m.surface);
}
}
}
}
if(pBackBuffer && pEffect && image[0].texture) {
struct Vertex {
float x, y, z, w, u, v;
} vertex[] = {
{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, },
{ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, },
{ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, },
{ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, },
};
vertex[1].x = vertex[3].x = (float) bbd.Width;
vertex[2].y = vertex[3].y = (float) bbd.Height;
if(SUCCEEDED(d->StretchRect(pBackBuffer, 0, image[0].surface, 0, D3DTEXF_NONE))) {
IDirect3DSurface9* originalRenderTarget = 0;
d->BeginScene();
d->GetRenderTarget(0, &originalRenderTarget);
for(int i = 0; i < maxPass; ++i) {
char tn[256];
wsprintfA(tn, "gTexture%d", i);
pEffect->SetTexture(tn, image[i].texture);
}
for(int pass = 0; pass < maxPass; ++pass) {
char tec[256];
wsprintfA(tec, "PostProcess%d", pass+1);
unsigned int passes = 0;
pEffect->SetTechnique(tec);
pEffect->Begin(&passes, 0);
pEffect->BeginPass(0);
d->SetRenderTarget(0, (pass == maxPass-1) ? originalRenderTarget : image[pass+1].surface);
d->SetFVF(D3DFVF_TEX1 | D3DFVF_XYZRHW);
d->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertex, sizeof(vertex[0]));
d->SetRenderTarget(0, 0);
pEffect->EndPass();
pEffect->End();
}
safeRelease(originalRenderTarget);
d->EndScene();
}
}
if(pBackBuffer) {
pBackBuffer->Release();
}
}
struct Image {
IDirect3DTexture9* texture;
IDirect3DSurface9* surface;
D3DSURFACE_DESC desc;
void release() {
safeRelease(surface);
safeRelease(texture);
memset(&desc, 0, sizeof(desc));
}
} image[256];
ID3DXEffect* pEffect;
int maxPass;
public:
static Effect* instance;
static void present(IDirect3DDevice9* device) {
if(! instance) {
instance = new Effect(device);
}
instance->draw(device);
}
static void reset(IDirect3DDevice9* device) {
if(instance) {
delete instance;
instance = 0;
}
}
};
Effect* Effect::instance = NULL;
int (WINAPI *o_D3DPERF_BeginEvent)(D3DCOLOR, LPCWSTR);
int (WINAPI *o_D3DPERF_EndEvent)();
DWORD (WINAPI *o_D3DPERF_GetStatus)();
BOOL (WINAPI *o_D3DPERF_QueryRepeatFrame)();
void (WINAPI *o_D3DPERF_SetMarker)(D3DCOLOR, LPCWSTR);
void (WINAPI *o_D3DPERF_SetOptions)(DWORD);
void (WINAPI *o_D3DPERF_SetRegion)(D3DCOLOR, LPCWSTR);
HRESULT (WINAPI *o_DebugSetLevel)();
HRESULT (WINAPI *o_DebugSetMute)(DWORD);
IDirect3D9* (WINAPI *o_Direct3DCreate9)(UINT);
HRESULT (WINAPI *o_Direct3DCreate9Ex)(UINT, IDirect3D9Ex**);
HRESULT (WINAPI *o_Direct3DShaderValidatorCreate9)();
HRESULT (WINAPI *o_PSGPError)();
HRESULT (WINAPI *o_PSGPSampleTexture)();
HRESULT (WINAPI *o_IDirect3D9_CreateDevice)(IDirect3D9*, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS*, IDirect3DDevice9**);
HRESULT (WINAPI *o_IDirect3DDevice9_Reset)(IDirect3DDevice9*, D3DPRESENT_PARAMETERS*);
HRESULT (WINAPI *o_IDirect3DDevice9_Present)(IDirect3DDevice9*, CONST RECT*, CONST RECT*, HWND, CONST RGNDATA*);
HRESULT (WINAPI *o_IDirect3DDevice9_BeginStateBlock)(IDirect3DDevice9*);
HRESULT (WINAPI *o_IDirect3DDevice9_EndStateBlock)(IDirect3DDevice9*, IDirect3DStateBlock9**);
void store_IDirect3DDevice9_function(IDirect3DDevice9* pDevice);
HRESULT WINAPI my_IDirect3DDevice9_Present(IDirect3DDevice9* device, const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion) {
Effect::present(device);
return o_IDirect3DDevice9_Present(device, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT WINAPI my_IDirect3DDevice9_Reset(IDirect3DDevice9* device, D3DPRESENT_PARAMETERS* pPresentationParameters) {
Effect::reset(device);
return o_IDirect3DDevice9_Reset(device, pPresentationParameters);
}
HRESULT WINAPI my_IDirect3DDevice9_BeginStateBlock(IDirect3DDevice9* device) {
HRESULT hr = o_IDirect3DDevice9_BeginStateBlock(device);
store_IDirect3DDevice9_function(device);
return hr;
}
HRESULT WINAPI my_IDirect3DDevice9_EndStateBlock(IDirect3DDevice9* device, IDirect3DStateBlock9** ppSB) {
HRESULT hr = o_IDirect3DDevice9_EndStateBlock(device, ppSB);
store_IDirect3DDevice9_function(device);
return hr;
}
void store_IDirect3DDevice9_function(IDirect3DDevice9* pDevice) {
MyInterface::IDirect3DDevice9Vtbl* v = ((MyInterface::IDirect3DDevice9*) pDevice)->lpVtbl;
DWORD protect = PAGE_EXECUTE_WRITECOPY;
VirtualProtect(v, sizeof(*v), protect, &protect);
* (void**) &v->Reset = (void*) my_IDirect3DDevice9_Reset;
* (void**) &v->Present = (void*) my_IDirect3DDevice9_Present;
* (void**) &v->BeginStateBlock = (void*) my_IDirect3DDevice9_BeginStateBlock;
* (void**) &v->EndStateBlock = (void*) my_IDirect3DDevice9_EndStateBlock;
VirtualProtect(v, sizeof(*v), protect, &protect);
}
HRESULT WINAPI my_IDirect3D9_CreateDevice(IDirect3D9* direct3d, UINT adapter, D3DDEVTYPE type, HWND window, DWORD flag, D3DPRESENT_PARAMETERS* param, IDirect3DDevice9** ppDevice) {
HRESULT hr = o_IDirect3D9_CreateDevice(direct3d, adapter, type, window, flag, param, ppDevice);
if(SUCCEEDED(hr)) {
MyInterface::IDirect3DDevice9Vtbl* v = ((MyInterface::IDirect3DDevice9*) (*ppDevice))->lpVtbl;
* (void**) &o_IDirect3DDevice9_Reset = (void*) v->Reset;
* (void**) &o_IDirect3DDevice9_Present = (void*) v->Present;
* (void**) &o_IDirect3DDevice9_BeginStateBlock = (void*) v->BeginStateBlock;
* (void**) &o_IDirect3DDevice9_EndStateBlock = (void*) v->EndStateBlock;
store_IDirect3DDevice9_function(*ppDevice);
}
return hr;
}
IDirect3D9* WINAPI Direct3DCreate9(UINT SDKVersion) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
IDirect3D9 *iDirect3D9 = o_Direct3DCreate9(SDKVersion);
if(iDirect3D9) {
OutputDebugString(_T("My Injection Test : d3d9.dll::Direct3DCreate9 - SUCCEEDED\n"));
MyInterface::IDirect3D9Vtbl* p = ((MyInterface::IDirect3D9*) iDirect3D9)->lpVtbl;
DWORD protect = PAGE_EXECUTE_WRITECOPY;
VirtualProtect(p, sizeof(*p), protect, &protect);
* (void**) &o_IDirect3D9_CreateDevice = (void*) p->CreateDevice;
* (void**) &p->CreateDevice = (void*) my_IDirect3D9_CreateDevice;
VirtualProtect(p, sizeof(*p), protect, &protect);
}
return iDirect3D9;
}
int WINAPI D3DPERF_EndEvent() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_EndEvent();
}
DWORD WINAPI D3DPERF_GetStatus() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_GetStatus();
}
BOOL WINAPI D3DPERF_QueryRepeatFrame() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_QueryRepeatFrame();
}
void WINAPI D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_SetMarker(col, wszName);
}
void WINAPI D3DPERF_SetOptions(DWORD dwOptions) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_SetOptions(dwOptions);
}
void WINAPI D3DPERF_SetRegion(D3DCOLOR col, LPCWSTR wszName) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_D3DPERF_SetRegion(col, wszName);
}
HRESULT WINAPI DebugSetLevel() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_DebugSetLevel();
}
HRESULT WINAPI DebugSetMute(DWORD dw1) {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_DebugSetMute(dw1);
}
HRESULT WINAPI Direct3DShaderValidatorCreate9() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_Direct3DShaderValidatorCreate9();
}
HRESULT WINAPI PSGPError() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_PSGPError();
}
HRESULT WINAPI PSGPSampleTexture() {
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return o_PSGPSampleTexture();
}
BOOL APIENTRY DllMain(HINSTANCE, DWORD fdwReason, LPVOID) {
if(fdwReason == DLL_PROCESS_ATTACH) {
TCHAR fn[MAX_PATH];
_tcscpy(fn + GetSystemDirectory(fn, _countof(fn)), _T("\\d3d9.dll"));
HMODULE h = LoadLibrary(fn);
* (void**) &o_D3DPERF_BeginEvent = GetProcAddress(h, "D3DPERF_BeginEvent");
* (void**) &o_D3DPERF_EndEvent = GetProcAddress(h, "D3DPERF_EndEvent");
* (void**) &o_D3DPERF_GetStatus = GetProcAddress(h, "D3DPERF_GetStatus");
* (void**) &o_D3DPERF_QueryRepeatFrame = GetProcAddress(h, "D3DPERF_QueryRepeatFrame");
* (void**) &o_D3DPERF_SetMarker = GetProcAddress(h, "D3DPERF_SetMarker");
* (void**) &o_D3DPERF_SetOptions = GetProcAddress(h, "D3DPERF_SetOptions");
* (void**) &o_D3DPERF_SetRegion = GetProcAddress(h, "D3DPERF_SetRegion");
* (void**) &o_DebugSetLevel = GetProcAddress(h, "DebugSetLevel");
* (void**) &o_DebugSetMute = GetProcAddress(h, "DebugSetMute");
* (void**) &o_Direct3DCreate9 = GetProcAddress(h, "Direct3DCreate9");
* (void**) &o_Direct3DCreate9Ex = GetProcAddress(h, "Direct3DCreate9Ex");
* (void**) &o_Direct3DShaderValidatorCreate9 = GetProcAddress(h, "Direct3DShaderValidatorCreate9");
* (void**) &o_PSGPError = GetProcAddress(h, "PSGPError");
* (void**) &o_PSGPSampleTexture = GetProcAddress(h, "PSGPSampleTexture");
}
return TRUE;
}
uniform extern texture gTexture0;
uniform extern texture gTexture1;
sampler pass1Sampler = sampler_state {
Texture = <gTexture0>;
MinFilter = POINT;
MagFilter = POINT;
MipFilter = POINT;
AddressU = BORDER;
AddressV = BORDER;
SRGBTexture = FALSE;
};
sampler pass2Sampler = sampler_state {
Texture = <gTexture1>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = NONE;
AddressU = BORDER;
AddressV = BORDER;
SRGBTexture = FALSE;
};
float4 Pass1Shader(float2 tex0 : TEXCOORD0) : COLOR0 {
float4 c0 = tex2D(pass1Sampler, tex0);
c0.x = 1.0;
return c0;
}
float4 Pass2Shader(float2 tex0 : TEXCOORD0) : COLOR0 {
float4 c0 = tex2D(pass2Sampler, tex0);
c0.z = 0.0;
return c0;
}
technique PostProcess1 {
pass p1 {
PixelShader = compile ps_3_0 Pass1Shader();
}
}
technique PostProcess2 {
pass p1 {
PixelShader = compile ps_3_0 Pass2Shader();
}
}