2022-12-17 18:51:43 chip
Page 2474
📢 PUBLIC
December 17 2022
The PxlShader project has grown to the point where it needs a bit
of organization.
Globals.h : Global declarations.
WinMain.cpp : WinMain() entry point.
PxlShader.cpp : Main window.
MyEffect.cpp : ID2D1EffectImpl
FirstShader.hlsl : Pixel shader code
Deploy.bat : Post-build batch file to copy files.
Globals.h contains all the declarations that span multiple modules.
TEXT Globals.h :
1 /*************************************************************************/
2 /** Globals.h: Global declarations for PxlShader. **/
3 /** (C)2022 nlited systems, cmd **/
4 /*************************************************************************/
5 #pragma once
6 #include <Windows.h>
7 #include <d2d1_1.h>
8 #include "StdTypes.h"
9 #include "Handles.h"
10 #include "Errors.h"
11
12 #define SIGNATURE_PXLSHADER 0xCD190001
13 #define SIGNATURE_MYEFFECT 0xCD190002
14 #define SIGNATURE_MYTRANSFORM 0xCD190003
15
16 using namespace D2D1;
17 typedef D2D1_POINT_2F POINT2D;
18
19 EXTERNC const GUID CLSID_MyEffect; // {D8255497-025E-4D3F-A4DF-5C25306F67AC}
20
21 #define SafeRelease(pInterface) { if(pInterface) pInterface->Release(); pInterface= 0; }
22 // SafeRelease call Release() only if pInterface is nonzero.
23 // pInterface is always set to zero, regardless the return value of Release().
24 // This is proper behavior because it is possible that some external process has
25 // a reference that will be released at some future time, but as far as I am
26 // concerned the interface has now ceased to exist.
27
28 //Auto-destruct solid brush.
29 class D2Brush {
30 public:
31 D2Brush(ID2D1RenderTarget *pRT, const D2D1_COLOR_F &clr) {
32 pRT->CreateSolidColorBrush(clr,&pbrBrush);
33 };
34 ~D2Brush(void) {
35 pbrBrush->Release();
36 }
37 operator ID2D1Brush *() { return(static_cast<ID2D1Brush*>(pbrBrush)); };
38 // This lets me use the object as the parameter to the various RenderTarget functions.
39 ID2D1SolidColorBrush *pbrBrush;
40 };
41
42 EXTERNC HINSTANCE ghInst;
43
44 extern int PxlShaderCreate(HWND &hWnd);
45
46 extern int MyEffectRegister(ID2D1Factory1 *pD2Factory);
47
48 //EOF: GLOBALS.H
WinMain() is the app's entry point.
TEXT WinMain.cpp :
1 /*************************************************************************/
2 /** WinMain.cpp: Windows entry point. **/
3 /** (C)2022 nlited systems, cmd **/
4 /*************************************************************************/
5 #include <Windows.h>
6 #include "Handles.h"
7 #include "ChipLib.h"
8 #include "Globals.h"
9
10 #pragma message(__FILE__": Optimizer disabled.")
11 #pragma optimize("",off)
12
13 HINSTANCE ghInst;
14 DWORD DbgFilter;
15
16 /*************************************************************************/
17 /** Window entry point **/
18 /*************************************************************************/
19 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pArgs, int nShow) {
20 int Err= ERR_OK;
21 HWND hWnd= 0;
22 ghInst= hInst;
23 MemCreate();
24 TmpBufCreate(16*1024*1024);
25 if(IsErr(Err= PxlShaderCreate(hWnd))) {
26 Err= Error(Err,"WinMain: Unable to create the main window.");
27 } else {
28 while(hWnd && IsWindow(hWnd)) {
29 MSG Msg;
30 GetMessage(&Msg,hWnd,0,0);
31 TranslateMessage(&Msg);
32 DispatchMessage(&Msg);
33 }
34 }
35 TmpBufDestroy();
36 MemDestroy();
37 if(IsErr(MemReport()))
38 MessageBox(0,L"PxlShader: Memory error.",L"PxlShader",MB_OK|MB_SETFOREGROUND);
39 return(Err);
40 }
41
42 void ConsolePrint(DWORD Type, const WCHAR *Text) {
43 TXT Out(0,0,"%s\r\n",Text);
44 OutputDebugString(Out);
45 }
46
47 //EOF: WINMAIN.CPP
PxlShader.cpp contains all the code to manage and render the main window.
TEXT PxlShader.cpp :
1 /*************************************************************************/
2 /** PxlShader.cpp: Minimal code to run a pixel shader. **/
3 /** (C)2022 nlited systems, cmd **/
4 /*************************************************************************/
5 #include <Windows.h>
6 #include <d3d11_1.h>
7 #include <d2d1_1.h>
8 #include "Globals.h"
9 #include "ChipLib.h"
10
11 #pragma message(__FILE__": Optimizer disabled.")
12 #pragma optimize("",off)
13
14 static const WCHAR WndClassName[]= { L"PxlShader" };
15
16 class PxlShader {
17 public:
18 static PxlShader *Ptr(void *pObj);
19 static PxlShader *Ptr(HWND hWnd);
20 static int Create(HWND &hWnd);
21 private:
22 PxlShader(void);
23 ~PxlShader(void);
24 int Create2(void);
25 static INT_PTR CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm);
26 LRESULT WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm);
27 int MsgCreate(HWND hWnd);
28 int MsgDestroy(void);
29 int MsgClose(void);
30 int MsgTimer(void);
31 int MsgMoved(void);
32 int MsgPaint(void);
33 int DrawCreate(void);
34 int DrawCreateDX(void);
35 int DrawCreateSwapChain(void);
36 int DrawCreateD2Factory(void);
37 int CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase);
38 int CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite);
39 int CreateEffect(void);
40 int DrawUpdate(void);
41 int DrawShow(void);
42 void ReleaseEverything(void);
43 //Data
44 DWORD Signature;
45 HWND hWnd;
46 RECT rWnd; // Window client area
47 POINT2D ptBall; // Bouncing ball position
48 POINT2D BallVector; // Bouncing ball vector
49 bool DoReset; // Call ReleaseEverything() before next draw.
50 D3D_FEATURE_LEVEL DxFeatures; // Supported feature set
51 IDXGIFactory2 *pDXGIFactory; // Creates SwapChain
52 IDXGISwapChain1 *pSwapChain; // Final display and pDXGISurface
53 IDXGISurface1 *pDXGISurface; // Used to create the bitmaps
54 IDXGIDevice *pDXGIDevice; // Base display device
55 ID2D1Factory1 *pD2Factory; // Creates Direct2D stuff
56 ID2D1Device *pD2Device; // Spawns ID2D1DeviceContext
57 ID2D1DeviceContext *pdcDraw; // The workhorse, used to draw everything.
58 ID2D1Bitmap1 *pbmImg; // Final offscreen image (write-only)
59 ID2D1Bitmap1 *pbmSrc1; // An intermediate offscreen image that can be composited.
60 ID2D1Bitmap1 *pbmSrc2; // An intermediate offscreen image that can be composited.
61 ID2D1Effect *pEffect; // Direct2D effect that contains my pixel shader.
62 };
63
64 int PxlShaderCreate(HWND &hWnd) {
65 return(PxlShader::Create(hWnd));
66 }
67
68 /*************************************************************************/
69 /** PxlShader class **/
70 /*************************************************************************/
71 PxlShader::PxlShader(void) {
72 Signature= SIGNATURE_PXLSHADER;
73 ptBall= { 10,20 };
74 BallVector= { 1,1 };
75 }
76
77 PxlShader::~PxlShader(void) {
78 Signature|= SIGNATURE_INVALID;
79 ReleaseEverything();
80 }
81
82 PxlShader *PxlShader::Ptr(void *pObj) {
83 PxlShader *pPxl= (PxlShader*)pObj;
84 if(!pObj || IsBadPtr(pObj,sizeof(*pPxl),BADPTR_RW) || pPxl->Signature!=SIGNATURE_PXLSHADER)
85 pPxl= 0;
86 return(pPxl);
87 }
88
89 PxlShader *PxlShader::Ptr(HWND hWnd) {
90 if(!hWnd || !IsWindow(hWnd))
91 return(0);
92 return(Ptr((void*)GetWindowLongPtr(hWnd,GWLP_USERDATA)));
93 }
94
95 int PxlShader::Create(HWND &hWnd) {
96 int Err= ERR_OK;
97 PxlShader *pPxl= new PxlShader;
98 if(!pPxl) {
99 Err= Error(ERR_NO_MEM,"PxlShader:Create: NoMem");
100 } else if(IsErr(Err= pPxl->Create2())) {
101 delete pPxl;
102 } else {
103 hWnd= pPxl->hWnd;
104 }
105 return(Err);
106 }
107
108 int PxlShader::Create2(void) {
109 int Err= ERR_OK;
110 ATOM hWndClass;
111 WNDCLASS WndClass;
112 RECT R= { 100,100,500,300 };
113 Zero(WndClass);
114 WndClass.style= CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
115 WndClass.lpfnWndProc= WndProc;
116 WndClass.hInstance= ghInst;
117 WndClass.lpszClassName= WndClassName;
118 DWORD style= WS_OVERLAPPEDWINDOW|WS_VISIBLE;
119 if(!(hWndClass= RegisterClass(&WndClass))) {
120 Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to register the main window class.");
121 } else if(!(hWnd= CreateWindow(WndClassName,L"PxlShader",style,R.left,R.top,RWID(R),RHGT(R),0,0,ghInst,(LPVOID)this))) {
122 Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to create the main window.");
123 }
124 return(Err);
125 }
126
127 /*************************************************************************/
128 /** Window message handler **/
129 /*************************************************************************/
130 INT_PTR CALLBACK PxlShader::WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) {
131 INT_PTR Result= 0;
132 PxlShader *pPxl= 0;
133 if(Msg==WM_CREATE) {
134 CREATESTRUCT *pCreate= (CREATESTRUCT*)lParm;
135 pPxl= Ptr(pCreate->lpCreateParams);
136 } else {
137 pPxl= Ptr(hWnd);
138 }
139 if(!pPxl) {
140 Result= DefWindowProc(hWnd,Msg,wParm,lParm);
141 } else {
142 Result= pPxl->WndProc2(hWnd,Msg,wParm,lParm);
143 }
144 return(Result);
145 }
146
147 LRESULT PxlShader::WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) {
148 LRESULT Result= 0;
149 switch(Msg) {
150 case WM_CREATE: Result= MsgCreate(hWnd); break;
151 case WM_DESTROY: Result= MsgDestroy(); break;
152 case WM_CLOSE: Result= MsgClose(); break;
153 case WM_TIMER: Result= MsgTimer(); break;
154 case WM_WINDOWPOSCHANGED: Result= MsgMoved(); break;
155 case WM_PAINT: Result= MsgPaint(); break;
156 default: Result= DefWindowProc(hWnd,Msg,wParm,lParm); break;
157 }
158 return(Result);
159 }
160
161 int PxlShader::MsgCreate(HWND _hWnd) {
162 hWnd= _hWnd;
163 SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)this);
164 SetTimer(hWnd,1,30,0);
165 return(1);
166 }
167
168 int PxlShader::MsgDestroy(void) {
169 SetWindowLongPtr(hWnd,GWLP_USERDATA,0);
170 delete this;
171 return(1);
172 }
173
174 int PxlShader::MsgClose(void) {
175 DestroyWindow(hWnd);
176 return(1);
177 }
178
179 int PxlShader::MsgTimer(void) {
180 ptBall.x+= BallVector.x;
181 if(ptBall.x < rWnd.left || ptBall.x >= rWnd.right) {
182 BallVector.x= -BallVector.x;
183 ptBall.x+= BallVector.x*2;
184 }
185 ptBall.y+= BallVector.y;
186 if(ptBall.y < rWnd.top || ptBall.y >= rWnd.bottom) {
187 BallVector.y= -BallVector.y;
188 ptBall.y+= BallVector.y*2;
189 }
190 if(pEffect) {
191 UINT32 Tint= ((UINT32)rand()<<16)|rand();
192 pEffect->SetValueByName(L"Tint",Tint);
193 }
194 InvalidateRect(hWnd,0,0);
195 return(1);
196 }
197
198 int PxlShader::MsgMoved(void) {
199 RECT rNew;
200 GetClientRect(hWnd,&rNew);
201 if(RWID(rNew)!=RWID(rWnd) || RHGT(rNew)!=RHGT(rWnd)) {
202 rWnd= rNew;
203 DoReset= true;
204 }
205 return(1);
206 }
207
208 int PxlShader::MsgPaint(void) {
209 int Err= ERR_OK;
210 PAINTSTRUCT Pnt;
211 GetClientRect(hWnd,&rWnd);
212 if(BeginPaint(hWnd,&Pnt)) {
213 if(IsErr(Err= DrawCreate())) {
214 Err= Warn(Err,"PxlShader:MsgPaint: DrawCreate() failed.");
215 } else if(IsErr(Err= DrawUpdate())) {
216 Err= Warn(Err,"PxlShader:MsgPaint: DrawUdpate() failed.");
217 } else if(IsErr(Err= DrawShow())) {
218 Err= Warn(Err,"PxlShader:MsgPaint: DrawPaint() failed.");
219 }
220 if(IsErr(Err)) {
221 // Fall back to GDI paint.
222 HBRUSH hbrFill= CreateSolidBrush(RGB(20,30,40));
223 FillRect(Pnt.hdc,&Pnt.rcPaint,hbrFill);
224 DeleteObject(hbrFill);
225 }
226 EndPaint(hWnd,&Pnt);
227 }
228 ValidateRect(hWnd,0);
229 return(1);
230 }
231
232 /*************************************************************************/
233 /** DirectX **/
234 /*************************************************************************/
235 int PxlShader::DrawCreate(void) {
236 int Err= ERR_OK;
237 HRESULT WinErr;
238 D2D1_SIZE_U szWnd= { (UINT32)RWID(rWnd), (UINT32)RHGT(rWnd) };
239 D2D1_DEVICE_CONTEXT_OPTIONS DCOptions= D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
240 if(DoReset)
241 ReleaseEverything();
242 if(!pDXGIDevice && IsErr(DrawCreateDX())) {
243 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create DXGI device.");
244 } else if(!pSwapChain && IsErr(Err= DrawCreateSwapChain())) {
245 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create SwapChain.");
246 } else if(!pDXGISurface && !SUCCEEDED(WinErr= pSwapChain->GetBuffer(0,IID_PPV_ARGS(&pDXGISurface)))) {
247 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to retrieve DXGI surface. [%X]",WinErr);
248 } else if(!pD2Factory && IsErr(Err= DrawCreateD2Factory())) {
249 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D factory.");
250 } else if(!pD2Device && !SUCCEEDED(WinErr= pD2Factory->CreateDevice(pDXGIDevice,&pD2Device))) {
251 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D device.");
252 } else if(!pdcDraw && !SUCCEEDED(WinErr= pD2Device->CreateDeviceContext(DCOptions,&pdcDraw))) {
253 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Draw context.");
254 } else if(!pbmImg && IsErr(Err= CreateBitmapBase(pdcDraw,szWnd,pbmImg))) {
255 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create base bitmap.");
256 } else if(!pEffect && IsErr(Err= CreateEffect())) {
257 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create MyEffect.");
258 } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) {
259 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap.");
260 } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) {
261 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap.");
262 }
263 return(Err);
264 }
265
266 int PxlShader::DrawCreateDX(void) {
267 int Err= ERR_OK;
268 HRESULT WinErr;
269 UINT Flags= D3D11_CREATE_DEVICE_BGRA_SUPPORT;
270 static const D3D_FEATURE_LEVEL Levels[]= {
271 D3D_FEATURE_LEVEL_11_1,
272 D3D_FEATURE_LEVEL_11_0,
273 D3D_FEATURE_LEVEL_10_1,
274 D3D_FEATURE_LEVEL_10_0,
275 D3D_FEATURE_LEVEL_9_3,
276 D3D_FEATURE_LEVEL_9_2,
277 D3D_FEATURE_LEVEL_9_1
278 };
279 D3D_DRIVER_TYPE Type= D3D_DRIVER_TYPE_HARDWARE;
280 UINT ctLevels= ARRAYSIZE(Levels);
281 UINT Version= D3D11_SDK_VERSION;
282 ID3D11Device *pD3D11Device= 0;
283 ID3D11DeviceContext *pD3D11DC= 0;
284 IDXGIAdapter *pDXGIAdapter= 0;
285 if(!SUCCEEDED(WinErr= D3D11CreateDevice(0,Type,0,Flags,Levels,ctLevels,Version,&pD3D11Device,&DxFeatures,&pD3D11DC))) {
286 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: D3D11CreateDevice() failed.");
287 } else if(!SUCCEEDED(WinErr= pD3D11Device->QueryInterface(&pDXGIDevice))) {
288 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI device. [%X]",WinErr);
289 } else if(!SUCCEEDED(WinErr= pDXGIDevice->GetAdapter(&pDXGIAdapter))) {
290 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI adapter. [%X]",WinErr);
291 } else if(!SUCCEEDED(WinErr= pDXGIAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory)))) {
292 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI factory. [%X]",WinErr);
293 }
294 //NOTE: pDXGIDevice has a RefCt of 3!
295 SafeRelease(pDXGIAdapter);
296 SafeRelease(pD3D11Device);
297 SafeRelease(pD3D11DC);
298 return(Err);
299 }
300
301 int PxlShader::DrawCreateSwapChain(void) {
302 int Err= ERR_OK;
303 HRESULT WinErr;
304 DXGI_SWAP_CHAIN_DESC1 SwapDesc;
305 Zero(SwapDesc);
306 SwapDesc.Format= DXGI_FORMAT_B8G8R8A8_UNORM;
307 SwapDesc.SampleDesc.Count= 1;
308 SwapDesc.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT;
309 SwapDesc.BufferCount= 2;
310 SwapDesc.Scaling= DXGI_SCALING_STRETCH;
311 SwapDesc.SwapEffect= DXGI_SWAP_EFFECT_DISCARD;
312 if(!SUCCEEDED(WinErr= pDXGIFactory->CreateSwapChainForHwnd(pDXGIDevice,hWnd,&SwapDesc,0,0,&pSwapChain))) {
313 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateSwapChain: Unable to create SwapChain. [%X]",WinErr);
314 }
315 return(Err);
316 }
317
318 int PxlShader::DrawCreateD2Factory(void) {
319 int Err= ERR_OK;
320 HRESULT WinErr;
321 REFIID guid= __uuidof(ID2D1Factory1);
322 D2D1_FACTORY_OPTIONS options;
323 options.debugLevel= D2D1_DEBUG_LEVEL_INFORMATION;
324 // DEBUG_LEVEL will trigger exceptions if EndDraw() fails or the factory is released with
325 // outstanding (unreleased) objects.
326 if(!SUCCEEDED(WinErr= D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,guid,&options,(void**)&pD2Factory))) {
327 Err= Error(ERR_DIRECTX,"PxlShader:DrawCreateD2Factory: Unable to create D2D factory. [%X]",WinErr);
328 }
329 return(Err);
330 }
331
332 // Create a targetable bitmap from a DXGI surface.
333 // This serves as the final rendering destination bitmap.
334 int PxlShader::CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase) {
335 int Err= ERR_OK;
336 HRESULT WinErr;
337 IDXGISurface *pSurface= 0;
338 D2D1_BITMAP_PROPERTIES1 bmProp;
339 Zero(bmProp);
340 bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET|D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
341 bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_IGNORE);
342 pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY);
343 if(!SUCCEEDED(WinErr= pdcDst->CreateBitmapFromDxgiSurface(pDXGISurface,bmProp,&pbmBase))) {
344 Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapBase: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height);
345 } else {
346 pdcDst->SetTarget(pbmBase);
347 }
348 return(Err);
349 }
350
351 // Create a targetable bitmap that can be used for compositing.
352 int PxlShader::CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite) {
353 int Err= ERR_OK;
354 HRESULT WinErr;
355 D2D1_BITMAP_PROPERTIES1 bmProp;
356 Zero(bmProp);
357 bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET;
358 bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED);
359 pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY);
360 if(!SUCCEEDED(WinErr= pdcDst->CreateBitmap(szBitmap,0,0,bmProp,&pbmComposite))) {
361 Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapComposite: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height);
362 } else {
363 pdcDst->SetTarget(pbmComposite);
364 }
365 return(Err);
366 }
367
368 int PxlShader::CreateEffect(void) {
369 int Err= ERR_OK;
370 HRESULT WinErr;
371 if(IsErr(Err= MyEffectRegister(pD2Factory))) {
372 Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to register MyEffect.");
373 } else if(!SUCCEEDED(WinErr= pdcDraw->CreateEffect(CLSID_MyEffect,&pEffect))) {
374 Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to create MyEffect. [%X]",WinErr);
375 } else {
376 Print(PRINT_INFO,"PxlShader:CreateEffect: OK");
377 }
378 return(Err);
379 }
380
381 void PxlShader::ReleaseEverything(void) {
382 SafeRelease(pEffect);
383 SafeRelease(pbmSrc2);
384 SafeRelease(pbmSrc1);
385 SafeRelease(pbmImg);
386 SafeRelease(pdcDraw);
387 SafeRelease(pD2Device);
388 SafeRelease(pD2Factory);
389 SafeRelease(pDXGISurface);
390 SafeRelease(pSwapChain);
391 SafeRelease(pDXGIFactory);
392 SafeRelease(pDXGIDevice);
393 DoReset= false;
394 }
395
396 /*************************************************************************/
397 /** Draw **/
398 /*************************************************************************/
399 int PxlShader::DrawUpdate(void) {
400 int Err= ERR_OK;
401 HRESULT WinErr;
402 if(!pdcDraw || !pbmImg || !pbmSrc1 || !pbmSrc2 || !pEffect) {
403 Err= Warn(ERR_NOT_CREATED,"PxlShader:DrawUpdate: No resources.");
404 } else {
405 pdcDraw->BeginDraw();
406 pdcDraw->SetTransform(Matrix3x2F::Identity());
407 pdcDraw->SetTarget(pbmSrc1);
408 pdcDraw->Clear(ColorF(ColorF::Black,0));
409 D2D1_RECT_F box= { 0,0,80,60 };
410 pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod)));
411 pdcDraw->SetTarget(pbmSrc2);
412 pdcDraw->Clear(ColorF(ColorF::Black,0));
413 D2D1_ELLIPSE dot= { {50,50}, 50,50 };
414 pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen)));
415 pdcDraw->SetTarget(pbmImg);
416 pdcDraw->Clear(ColorF(ColorF::Black,0));
417 pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y)));
418 pEffect->SetInput(0,pbmSrc1);
419 pEffect->SetInput(1,pbmSrc2);
420 pdcDraw->DrawImage(pEffect);
421 if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) {
422 Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr);
423 DoReset= true;
424 }
425 }
426 return(Err);
427 }
428
429 int PxlShader::DrawShow(void) {
430 int Err= ERR_OK;
431 HRESULT WinErr;
432 DXGI_PRESENT_PARAMETERS PresentParm;
433 Zero(PresentParm);
434 if(!pSwapChain) {
435 Err= Warn(ERR_NOT_CREATED,"PxlShader:DrawShow: No SwapChain.");
436 } else if(!SUCCEEDED(WinErr= pSwapChain->Present1(1,0,&PresentParm))) {
437 Err= Warn(ERR_DIRECTX,"PxlShader:DrawShow: Present() failed. [%X]",WinErr);
438 DoReset= true;
439 }
440 return(Err);
441 }
442
443 //EOF: PXLSHADER.CPP
MyEffect.cpp contains all the code to implement my custom Direct2D Effect.
TEXT MyEffect.cpp :
1 /*************************************************************************/
2 /** MyEffect.cpp: A simple pixel shader wrapped inside ID2D1Effect. **/
3 /** (C)2022 nlited systems, cmd **/
4 /*************************************************************************/
5 #include <Windows.h>
6 #include <d3d11_1.h>
7 #include <d2d1.h>
8 #include <d2d1_1.h>
9 #include <d2d1helper.h>
10 #include <d2d1effectauthor.h>
11 #include <d2d1effecthelpers.h>
12 #include <d3dcompiler.h>
13 #include "Globals.h"
14 #include "ChipLib.h"
15
16 #pragma comment(lib,"D3D11.lib")
17 #pragma comment(lib,"D2D1.lib")
18 #pragma comment(lib,"DXGI.lib")
19 #pragma comment(lib,"d3dcompiler.lib")
20
21 #pragma message(__FILE__": Optimizer disabled.")
22 #pragma optimize("",off)
23
24 // {D8255497-025E-4D3F-A4DF-5C25306F67AC}
25 const GUID CLSID_MyEffect = { 0xd8255497, 0x25e, 0x4d3f, { 0xa4, 0xdf, 0x5c, 0x25, 0x30, 0x6f, 0x67, 0xac } };
26
27 // {2BCB702A-4F42-44D0-B8ED-4E9F9FC7A905}
28 static const GUID GUID_MyPixelShader = { 0x2bcb702a, 0x4f42, 0x44d0, { 0xb8, 0xed, 0x4e, 0x9f, 0x9f, 0xc7, 0xa9, 0x5 } };
29
30 #define MAX_INPUT 2
31
32 class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform {
33 public:
34 //EffectImpl
35 static HRESULT Register(_In_ ID2D1Factory1 *pFactory);
36 static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect);
37 IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface);
38 IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); };
39 IFACEMETHODIMP_(ULONG) Release(void);
40 IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph);
41 IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type);
42 IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph);
43 //DrawTransform
44 IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw);
45 IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const;
46 IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque);
47 IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const;
48 IFACEMETHODIMP_(UINT32) GetInputCount(void) const;
49 //Added
50 HRESULT SetTint(UINT32 Clr);
51 UINT32 GetTint(void) const;
52 private:
53 MyEffect(void);
54 ~MyEffect(void);
55 // Data
56 DWORD Signature;
57 LONG ctReference;
58 ID2D1EffectContext *pCtx;
59 ID2D1DrawInfo *pDraw;
60 UINT ctInput;
61 D2D1_RECT_L rIn[MAX_INPUT];
62 struct ShaderConstant_s {
63 float tint[4];
64 } Constants;
65 };
66
67 /*************************************************************************/
68 /** Public interface **/
69 /*************************************************************************/
70 int MyEffectRegister(ID2D1Factory1 *pD2Factory) {
71 return(MyEffect::Register(pD2Factory));
72 }
73
74 /*************************************************************************/
75 /** Private code **/
76 /*************************************************************************/
77 MyEffect::MyEffect(void) {
78 Signature= SIGNATURE_MYEFFECT;
79 ctReference= 1;
80 ctInput= 0;
81 Zero(Constants);
82 Constants.tint[2]= 0.50f;
83 }
84
85 MyEffect::~MyEffect(void) {
86 Signature|= SIGNATURE_INVALID;
87 }
88
89 ULONG MyEffect::Release(void) {
90 if(--ctReference > 0)
91 return(ctReference);
92 delete this;
93 return(0);
94 }
95
96 HRESULT MyEffect::QueryInterface(REFIID riid, void **ppInterface) {
97 HRESULT WinErr= S_OK;
98 void *pInterface= 0;
99 if(riid==__uuidof(ID2D1EffectImpl)) {
100 pInterface= reinterpret_cast<ID2D1EffectImpl*>(this);
101 } else if(riid==__uuidof(ID2D1DrawTransform)) {
102 pInterface= static_cast<ID2D1DrawTransform*>(this);
103 } else if(riid==__uuidof(ID2D1Transform)) {
104 pInterface= static_cast<ID2D1Transform*>(this);
105 } else if(riid==__uuidof(ID2D1TransformNode)) {
106 pInterface= static_cast<ID2D1TransformNode*>(this);
107 } else if(riid==__uuidof(ID2D1ComputeTransform)) {
108 Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a compute transform.");
109 WinErr= E_NOINTERFACE;
110 } else if(riid==__uuidof(ID2D1SourceTransform)) {
111 Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a source transform.");
112 WinErr= E_NOINTERFACE;
113 } else if(riid==__uuidof(IUnknown)) {
114 pInterface= this;
115 } else {
116 WinErr= E_NOINTERFACE;
117 }
118 if(ppInterface) {
119 *ppInterface= pInterface;
120 if(pInterface)
121 AddRef();
122 }
123 return(WinErr);
124 }
125
126 HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) {
127 HRESULT WinErr= S_OK;
128 static const PCWSTR pszXml =
129 L"<?xml version='1.0'?>\r\n"
130 L"<Effect>\r\n"
131 L" <!-- System Properties -->\r\n"
132 L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n"
133 L" <Property name='Author' type='string' value='nlited systems'/>\r\n"
134 L" <Property name='Category' type='string' value='Experimental'/>\r\n"
135 L" <Property name='Description' type='string' value='My first effect.'/>\r\n"
136 L" <Inputs minimum='0' maximum='2'>\r\n"
137 // Source must be specified.
138 L" <Input name='Source1'/>\r\n"
139 L" <Input name='Source2'/>\r\n"
140 L" </Inputs>\r\n"
141 L" <!-- Custom Properties go here. -->\r\n"
142 L" <Property name='Tint' type='uint32'>\r\n"
143 L" <Property name='DisplayName' type='string' value='Tint'/>\r\n"
144 L" <Property name='Default' type='uint32' value='0'/>\r\n"
145 L" </Property>\r\n"
146 L"</Effect>\r\n"
147 ;
148 static const D2D1_PROPERTY_BINDING Bindings[]= {
149 D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint)
150 };
151 if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) {
152 Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr);
153 }
154 return(WinErr);
155 }
156
157 HRESULT __stdcall MyEffect::CreateMyEffect(IUnknown **ppEffect) {
158 HRESULT WinErr= S_OK;
159 *ppEffect= static_cast<ID2D1EffectImpl*>(new MyEffect);
160 if(!*ppEffect) {
161 WinErr= E_OUTOFMEMORY;
162 }
163 return(WinErr);
164 }
165
166 HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) {
167 HRESULT WinErr= S_OK;
168 ID3DBlob *pCode= 0;
169 ID3DBlob *pError= 0;
170 pCtx= _pCtx;
171 if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"FirstShader.cso",&pCode))) {
172 Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr);
173 } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) {
174 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr);
175 } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) {
176 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr);
177 } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) {
178 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr);
179 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) {
180 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr);
181 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) {
182 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr);
183 } else {
184 ctInput= 2;
185 Print(PRINT_INFO,"MyEffect:Initialize: OK.");
186 }
187 SafeRelease(pCode);
188 SafeRelease(pError);
189 return(WinErr);
190 }
191
192 // This is a single-transform, single-node graph, SetGraph() should never be called.
193 HRESULT MyEffect::SetGraph(ID2D1TransformGraph *pGraph) {
194 Warn(ERR_DIRECTX,"MyEffect:SetGraph: Should not be called.");
195 return(E_NOTIMPL);
196 }
197
198 HRESULT MyEffect::SetTint(UINT32 Clr) {
199 Constants.tint[0]= (float)((Clr>>16) & 0xFF)/255.0f;
200 Constants.tint[1]= (float)((Clr>> 8) & 0xFF)/255.0f;
201 Constants.tint[2]= (float)((Clr ) & 0xFF)/255.0f;
202 Constants.tint[3]= (float)((Clr>>24) & 0xFF)/255.0f;
203 return(S_OK);
204 }
205
206 UINT32 MyEffect::GetTint(void) const {
207 UINT32 Clr= 0;
208 Clr|= ((UINT32)(Constants.tint[0]*255.0f) & 0xFF)<<16;
209 Clr|= ((UINT32)(Constants.tint[1]*255.0f) & 0xFF)<< 8;
210 Clr|= ((UINT32)(Constants.tint[2]*255.0f) & 0xFF);
211 Clr|= ((UINT32)(Constants.tint[3]*255.0f) & 0xFF)<<24;
212 return(Clr);
213 }
214
215 HRESULT MyEffect::PrepareForRender(D2D1_CHANGE_TYPE Type) {
216 HRESULT WinErr= S_OK;
217 pDraw->SetPixelShaderConstantBuffer((BYTE*)&Constants,sizeof(Constants));
218 return(WinErr);
219 }
220
221 // ID2D1DrawTransform
222 HRESULT MyEffect::SetDrawInfo(ID2D1DrawInfo *_pDraw) {
223 HRESULT WinErr= S_OK;
224 pDraw= _pDraw;
225 if(!SUCCEEDED(WinErr= pDraw->SetPixelShader(GUID_MyPixelShader))) {
226 Warn(ERR_DIRECTX,"MyEffect:SetDrawInfo: SetPixelShader() failed. [%X]",WinErr);
227 }
228 return(WinErr);
229 }
230
231 HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const {
232 HRESULT WinErr= S_OK;
233 //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn);
234 if(ctIn==0) {
235 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?");
236 } else if(ctIn>MAX_INPUT) {
237 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn);
238 WinErr= E_INVALIDARG;
239 } else if(ctIn>0) {
240 prIn[0]= *prOut;
241 for(UINT n1=1;n1<ctIn;n1++) {
242 prIn[n1]= *prOut;
243 }
244 }
245 return(WinErr);
246 }
247
248 IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) {
249 HRESULT WinErr= S_OK;
250 //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn);
251 if(ctIn==0) {
252 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?");
253 } else if(ctIn>MAX_INPUT) {
254 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn);
255 WinErr= E_INVALIDARG;
256 } else if(ctIn>0) {
257 *prOut= rIn[0]= prIn[0];
258 for(UINT n1=1;n1<ctIn;n1++) {
259 rIn[n1]= prIn[n1];
260 }
261 Zero(*prOutOpaque);
262 }
263 return(WinErr);
264 }
265
266 IFACEMETHODIMP MyEffect::MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOutInvalid) const {
267 HRESULT WinErr= S_OK;
268 Print(PRINT_DEBUG,"MyEffect:MapInvalidRect:");
269 // Set entire output to invalid
270 *prOutInvalid= rIn[0];
271 return(WinErr);
272 }
273
274 IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const {
275 return(MAX_INPUT);
276 }
277
278 //EOF: MYEFFECT.CPP
FirstShader.hlsl contains the pixel shader code that will run on the GPU.
TEXT FirstShader.hlsl :
1 /*************************************************************************/
2 /** FirstShader.hlsl: My First Pixel Shader. **/
3 /** (C)2022 nlited systems, cmd **/
4 /*************************************************************************/
5 #define D2D_INPUT_COUNT 2
6 #include "d2d1effecthelpers.hlsli"
7
8 cbuffer constants: register(b0) {
9 float4 tint:COLOR;
10 };
11
12 D2D_PS_ENTRY(main) {
13 float4 color= 0;
14 float4 color0= D2DGetInput(0);
15 float4 color1= D2DGetInput(1);
16 if(color0.a && color1.a) {
17 color= (color0+color1*2)/3;
18 } else if(color0.a) {
19 color= (color0+tint)/2;
20 } else if(color1.a) {
21 color= (color1+tint)/2;
22 }
23 return color;
24 }
25
26 //EOF: FIRSTSHADER.HLSL
Deploy.bat runs post-build to copy the FirstShader.cso shader binary file
to the Test directory, which will be the current directory when PxlShader.exe
runs.
TEXT Deploy.bat :
1 REM %1 Execution directory $(SolutionDir)Test
2 REM %2 Output directory $(OutDir)
3 echo %1 %2
4 copy /y "%2\FirstShader.cso" "%1"
WebV7 (C)2018 nlited | Rendered by tikope in 163.753ms | 3.142.220.14