本来打算用Shader Model 2.0,但是经过测试,Shader Model 2.0的功能太原始,连for循环都无法支持,最后只能改用Shader Model 3.0。由于使用了HLSL编译Shader Model 3.0,所以需要VS2002-2010和DirectX 9.0c SDK 2004-2010, 不能使用VC6和DirectX 9.0b SDK。
DX是DirectX的缩写,SM是Shader Model的缩写。
如果改写成DirectX 10/11版本的话,最低应该需要D3D_FEATURE_LEVEL_9_3和ps_4_0_level_9_3,同时还需要编写一个简易的vs_4_0_level_9_3,因为vertex shader和pixel shader在10/11中都不是可选的。
但是由于vs_4_0_level_9_3和ps_4_0_level_9_3不支持通用循环,需要把循环展开成多次条件判断,512的指令数很容易就用超了,对于较复杂的运算,最低建议使用D3D_FEATURE_LEVEL_10_0、vs_4_0和ps_4_0。
<code class="language-txt">vs_1_1 - 128指令 vs_2_0 - 256指令 vs_4_0_level_9_1 - 256指令 vs_2_x - 256指令 vs_4_0_level_9_3 - 256指令 vs_3_0 - 最少512指令,上限到D3DCAPS9.MaxVertexShader30InstructionSlots,支持通用循环 vs_4_0 - 无限制,支持通用循环 ps_2_0 - 32纹理指令+64算术指令 ps_4_0_level_9_1 - 32纹理指令+64算术指令 ps_2_x - 最少96指令,上限到D3DCAPS9.D3DPSHADERCAPS2_0.NumInstructionSlots ps_4_0_level_9_3 - 512指令 vs_3_0 - 最少512指令,上限到D3DCAPS9.MaxPixelShader30InstructionSlots,支持通用循环 vs_4_0 - 无限制,支持通用循环 </code>
GPU部分:
<code class="language-c">// complexsets.txt float4 ps_mandelbrot(float2 tex : TEXCOORD0) : COLOR0 { float2 zvar = float2(0, 0); float i; for (i = 0; i < 16 && zvar.x * zvar.x + zvar.y * zvar.y <= 16 4; i++) { float2 zvar2="zvar;" zvar.x="zvar2.x" * zvar2.x - zvar2.y + tex.x; zvar.y="zvar2.x" tex.y; } return float4(i 16.0, 0.0f, 1.0f); float4 ps_julia(float2 tex : texcoord0) color0 zvar="tex;" float i; for (i="0;" i < && 0.4f; 0.3f; code></=></code>
CPU部分:
<code class="language-c">// main.c #include <windows.h> #include <tchar.h> // DirectX 9.0c SDK or higher #include <d3d9.h> #include <d3dx9.h> #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") #pragma comment(linker, "/nodefaultlib:libcp") LPDIRECT3D9 g_pD3D = NULL; LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; LPDIRECT3DPIXELSHADER9 g_pPSmandelbrot = NULL; LPDIRECT3DPIXELSHADER9 g_pPSjulia = NULL; LPDIRECT3DPIXELSHADER9 g_pPS = NULL; typedef struct CUSTOMVERTEX { FLOAT x, y, z, rhw; FLOAT u, v; }CUSTOMVERTEX; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1) HRESULT InitD3D(HWND hWnd) { D3DPRESENT_PARAMETERS d3dpp; if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; if (FAILED(IDirect3D9_CreateDevice(g_pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice))) { return E_FAIL; } return S_OK; } HRESULT CompileAndCreatePS(LPCTSTR filename, LPSTR funcname, LPDIRECT3DPIXELSHADER9 *pps) { LPD3DXBUFFER psbuf = NULL, errmsg = NULL; HRESULT hr = S_OK; hr = D3DXCompileShaderFromFile(filename, NULL, NULL, funcname, "ps_3_0", 0, &psbuf, &errmsg, NULL); if (errmsg) { MessageBoxA(NULL, (char*)errmsg->lpVtbl->GetBufferPointer(errmsg), "err", MB_ICONERROR); errmsg->lpVtbl->Release(errmsg); return hr; } else if (FAILED(hr)) { return hr; } hr = IDirect3DDevice9_CreatePixelShader(g_pd3dDevice, (DWORD*)psbuf->lpVtbl->GetBufferPointer(psbuf), pps); psbuf->lpVtbl->Release(psbuf); return S_OK; } HRESULT InitRes() { CUSTOMVERTEX vertices[] = { { 0.0f, 0.0f, 0.5f, 1.0f, -2.2f, -2.2f, }, { 480.0f, 0.0f, 0.5f, 1.0f, 2.2f, -2.2f, }, { 0.0f, 480.0f, 0.5f, 1.0f, -2.2f, 2.2f, }, { 480.0f, 480.0f, 0.5f, 1.0f, 2.2f, 2.2f, }, }; HRESULT hr = S_OK; VOID* pVertices; hr = IDirect3DDevice9_CreateVertexBuffer(g_pd3dDevice, 4*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL); if (FAILED(hr)) { return hr; } hr = IDirect3DVertexBuffer9_Lock(g_pVB, 0, sizeof(vertices), (void**)&pVertices, 0); if (FAILED(hr)) return hr; memcpy(pVertices, vertices, sizeof(vertices)); IDirect3DVertexBuffer9_Unlock(g_pVB); CompileAndCreatePS(_T("complexsets.txt"), "ps_mandelbrot", &g_pPSmandelbrot); CompileAndCreatePS(_T("complexsets.txt"), "ps_julia", &g_pPSjulia); g_pPS = g_pPSmandelbrot; return S_OK; } VOID Cleanup() { if (g_pPSjulia) IDirect3DPixelShader9_Release(g_pPSjulia); if (g_pPSmandelbrot) IDirect3DPixelShader9_Release(g_pPSmandelbrot); if (g_pVB != NULL) IDirect3DVertexBuffer9_Release(g_pVB); if (g_pd3dDevice != NULL) IDirect3DDevice9_Release(g_pd3dDevice); if (g_pD3D != NULL) IDirect3D9_Release(g_pD3D); } VOID Render() { IDirect3DDevice9_Clear(g_pd3dDevice, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0); if (SUCCEEDED(IDirect3DDevice9_BeginScene(g_pd3dDevice))) { IDirect3DDevice9_SetStreamSource(g_pd3dDevice, 0, g_pVB, 0, sizeof(CUSTOMVERTEX)); IDirect3DDevice9_SetFVF(g_pd3dDevice, D3DFVF_CUSTOMVERTEX); IDirect3DDevice9_SetPixelShader(g_pd3dDevice, g_pPS); IDirect3DDevice9_DrawPrimitive(g_pd3dDevice, D3DPT_TRIANGLESTRIP, 0, 2); IDirect3DDevice9_EndScene(g_pd3dDevice); } IDirect3DDevice9_Present(g_pd3dDevice, NULL, NULL, NULL, NULL); } LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_LBUTTONDOWN: g_pPS = g_pPSmandelbrot; return 0; case WM_RBUTTONDOWN: g_pPS = g_pPSjulia; return 0; case WM_DESTROY: Cleanup(); PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nShowCmd) { WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, hInst, LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW), NULL, NULL, _T("MainWndProc"), wc.hIcon }; RECT rc = { 0, 0, 480, 480 }; MSG msg; HWND hWnd; if (!RegisterClassEx(&wc)) return 0; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); hWnd = CreateWindow(wc.lpszClassName, _T("Mandelbrot and Julia"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, wc.hInstance, NULL); if (SUCCEEDED(InitD3D(hWnd))) { if (SUCCEEDED(InitRes())) { ShowWindow(hWnd, SW_SHOWDEFAULT); UpdateWindow(hWnd); ZeroMemory(&msg, sizeof(msg)); while (msg.message != WM_QUIT) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { Render(); } } } } return 0; } </d3dx9.h></d3d9.h></tchar.h></windows.h></code>
更新:支持Visual C++ 6.0和DirectX 9.0b SDK
通过DirectX 9.0c SDK的fxc将上述HLSL代码编译为Shader Model 3.0 ASM代码,即可支持DirectX 9.0b SDK。
ps_mandelbrot.txt:
<code class="language-asm">// ps_mandelbrot.txt ps_3_0 def c0, 0, 0, 4, 1 def c1, 0.0625, 0, 0, 0 defi i0, 16, 0, 0, 0 dcl_texcoord v0.xy mov r0.y, c0.y mov r0.z, c0.y mov r0.w, c0.y rep i0 mul r0.x, r0.z, r0.z mad r0.x, r0.y, r0.y, r0.x break_lt c0.z, r0.x mul r0.x, r0.z, r0.z mad r0.x, r0.y, r0.y, -r0.x add r0.x, r0.x, v0.x dp2add r0.z, r0.y, r0.z, v0.y add r0.w, r0.w, c0.w mov r0.y, r0.x endrep mul oC0.x, r0.w, c1.x mov oC0.yzw, c0.xyyw </code>
ps_julia.txt
<code class="language-asm">// ps_julia.txt ps_3_0 def c0, 0, 0, 4, 0.400000006 def c1, 0.300000012, 1, 0.0625, 0 defi i0, 16, 0, 0, 0 dcl_texcoord v0.xy mov r0.y, v0.x mov r0.z, v0.y mov r0.w, c0.y rep i0 mul r0.x, r0.z, r0.z mad r0.x, r0.y, r0.y, r0.x break_lt c0.z, r0.x mul r0.x, r0.z, r0.z mad r0.x, r0.y, r0.y, -r0.x add r0.x, r0.x, c0.w dp2add r0.z, r0.y, r0.z, c1.x add r0.w, r0.w, c1.y mov r0.y, r0.x endrep mul oC0.x, r0.w, c1.z mov oC0.yzw, c1.xwwy </code>
main.c
<code class="language-c">// main.c #include <windows.h> #include <tchar.h> #include <d3d9.h> #include <d3dx9.h> #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") LPDIRECT3D9 g_pD3D = NULL; LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; LPDIRECT3DPIXELSHADER9 g_pPSmandelbrot = NULL; LPDIRECT3DPIXELSHADER9 g_pPSjulia = NULL; LPDIRECT3DPIXELSHADER9 g_pPS = NULL; typedef struct CUSTOMVERTEX { FLOAT x, y, z, rhw; FLOAT u, v; }CUSTOMVERTEX; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1) HRESULT InitD3D(HWND hWnd) { D3DPRESENT_PARAMETERS d3dpp; if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; if (FAILED(IDirect3D9_CreateDevice(g_pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice))) { return E_FAIL; } return S_OK; } HRESULT AssembleAndCreatePS(LPCTSTR filename, LPDIRECT3DPIXELSHADER9 *pps) { LPD3DXBUFFER psbuf = NULL, errmsg = NULL; HRESULT hr = S_OK; hr = D3DXAssembleShaderFromFile(filename, NULL, NULL, 0, &psbuf, &errmsg); if (errmsg) { MessageBoxA(NULL, (char*)errmsg->lpVtbl->GetBufferPointer(errmsg), "err", MB_ICONERROR); errmsg->lpVtbl->Release(errmsg); return hr; } else if (FAILED(hr)) { return hr; } hr = IDirect3DDevice9_CreatePixelShader(g_pd3dDevice, (DWORD*)psbuf->lpVtbl->GetBufferPointer(psbuf), pps); psbuf->lpVtbl->Release(psbuf); return S_OK; } HRESULT InitRes() { CUSTOMVERTEX vertices[] = { { 0.0f, 0.0f, 0.5f, 1.0f, -2.2f, -2.2f, }, { 480.0f, 0.0f, 0.5f, 1.0f, 2.2f, -2.2f, }, { 0.0f, 480.0f, 0.5f, 1.0f, -2.2f, 2.2f, }, { 480.0f, 480.0f, 0.5f, 1.0f, 2.2f, 2.2f, }, }; HRESULT hr = S_OK; VOID* pVertices; hr = IDirect3DDevice9_CreateVertexBuffer(g_pd3dDevice, 4*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL); if (FAILED(hr)) { return hr; } hr = IDirect3DVertexBuffer9_Lock(g_pVB, 0, sizeof(vertices), (void**)&pVertices, 0); if (FAILED(hr)) return hr; memcpy(pVertices, vertices, sizeof(vertices)); IDirect3DVertexBuffer9_Unlock(g_pVB); AssembleAndCreatePS(_T("ps_mandelbrot.txt"), &g_pPSmandelbrot); AssembleAndCreatePS(_T("ps_julia.txt"), &g_pPSjulia); g_pPS = g_pPSmandelbrot; return S_OK; } VOID Cleanup() { if (g_pPSjulia) IDirect3DPixelShader9_Release(g_pPSjulia); if (g_pPSmandelbrot) IDirect3DPixelShader9_Release(g_pPSmandelbrot); if (g_pVB != NULL) IDirect3DVertexBuffer9_Release(g_pVB); if (g_pd3dDevice != NULL) IDirect3DDevice9_Release(g_pd3dDevice); if (g_pD3D != NULL) IDirect3D9_Release(g_pD3D); } VOID Render() { IDirect3DDevice9_Clear(g_pd3dDevice, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0); if (SUCCEEDED(IDirect3DDevice9_BeginScene(g_pd3dDevice))) { IDirect3DDevice9_SetStreamSource(g_pd3dDevice, 0, g_pVB, 0, sizeof(CUSTOMVERTEX)); IDirect3DDevice9_SetFVF(g_pd3dDevice, D3DFVF_CUSTOMVERTEX); IDirect3DDevice9_SetPixelShader(g_pd3dDevice, g_pPS); IDirect3DDevice9_DrawPrimitive(g_pd3dDevice, D3DPT_TRIANGLESTRIP, 0, 2); IDirect3DDevice9_EndScene(g_pd3dDevice); } IDirect3DDevice9_Present(g_pd3dDevice, NULL, NULL, NULL, NULL); } LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_LBUTTONDOWN: g_pPS = g_pPSmandelbrot; return 0; case WM_RBUTTONDOWN: g_pPS = g_pPSjulia; return 0; case WM_DESTROY: Cleanup(); PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nShowCmd) { WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, hInst, LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW), NULL, NULL, _T("MainWndProc"), wc.hIcon }; RECT rc = { 0, 0, 480, 480 }; MSG msg; HWND hWnd; if (!RegisterClassEx(&wc)) return 0; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); hWnd = CreateWindow(wc.lpszClassName, _T("Mandelbrot and Julia"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, wc.hInstance, NULL); if (SUCCEEDED(InitD3D(hWnd))) { if (SUCCEEDED(InitRes())) { ShowWindow(hWnd, SW_SHOWDEFAULT); UpdateWindow(hWnd); ZeroMemory(&msg, sizeof(msg)); while (msg.message != WM_QUIT) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { Render(); } } } } return 0; } </d3dx9.h></d3d9.h></tchar.h></windows.h></code>
[修改于 7年4个月前 - 2017/08/11 21:27:30]
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |