dev.nlited.com

>>

Reorg

<<<< prev
next >>>>

2022-12-17 18:51:43 chip Page 2474 📢 PUBLIC

December 17 2022

PxlShader reorg

The PxlShader project has grown to the point where it needs a bit of organization.

  1. Globals.h: Global declarations.
  2. WinMain.cpp: WinMain() entry point.
  3. PxlShader.cpp: Main window.
  4. MyEffect.cpp: ID2D1EffectImpl
  5. FirstShader.hlsl: Pixel shader code
  6. Deploy.bat: Post-build batch file to copy files.

Globals.h contains all the declarations that span multiple modules.


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 16using namespace D2D1; 17typedef D2D1_POINT_2F POINT2D; 18 19EXTERNC 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. 29class D2Brush { 30public: 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 42EXTERNC HINSTANCE ghInst; 43 44extern int PxlShaderCreate(HWND &hWnd); 45 46extern int MyEffectRegister(ID2D1Factory1 *pD2Factory); 47 48 //EOF: GLOBALS.H

WinMain() is the app's entry point.

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 13HINSTANCE ghInst; 14DWORD DbgFilter; 15 16/*************************************************************************/ 17/** Window entry point **/ 18/*************************************************************************/ 19int 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 42void 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.

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 14static const WCHAR WndClassName[]= { L"PxlShader" }; 15 16class PxlShader { 17public: 18 static PxlShader *Ptr(void *pObj); 19 static PxlShader *Ptr(HWND hWnd); 20 static int Create(HWND &hWnd); 21private: 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 64int PxlShaderCreate(HWND &hWnd) { 65 return(PxlShader::Create(hWnd)); 66} 67 68/*************************************************************************/ 69/** PxlShader class **/ 70/*************************************************************************/ 71PxlShader::PxlShader(void) { 72 Signature= SIGNATURE_PXLSHADER; 73 ptBall= { 10,20 }; 74 BallVector= { 1,1 }; 75} 76 77PxlShader::~PxlShader(void) { 78 Signature|= SIGNATURE_INVALID; 79 ReleaseEverything(); 80} 81 82PxlShader *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 89PxlShader *PxlShader::Ptr(HWND hWnd) { 90 if(!hWnd || !IsWindow(hWnd)) 91 return(0); 92 return(Ptr((void*)GetWindowLongPtr(hWnd,GWLP_USERDATA))); 93} 94 95int 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 108int 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/*************************************************************************/ 130INT_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 147LRESULT 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 161int 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 168int PxlShader::MsgDestroy(void) { 169 SetWindowLongPtr(hWnd,GWLP_USERDATA,0); 170 delete this; 171 return(1); 172} 173 174int PxlShader::MsgClose(void) { 175 DestroyWindow(hWnd); 176 return(1); 177} 178 179int 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 198int 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 208int 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/*************************************************************************/ 235int 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 266int 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 301int 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 318int 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. 334int 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. 352int 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 368int 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 381void 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/*************************************************************************/ 399int 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 429int 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.

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} 25const GUID CLSID_MyEffect = { 0xd8255497, 0x25e, 0x4d3f, { 0xa4, 0xdf, 0x5c, 0x25, 0x30, 0x6f, 0x67, 0xac } }; 26 27 // {2BCB702A-4F42-44D0-B8ED-4E9F9FC7A905} 28static const GUID GUID_MyPixelShader = { 0x2bcb702a, 0x4f42, 0x44d0, { 0xb8, 0xed, 0x4e, 0x9f, 0x9f, 0xc7, 0xa9, 0x5 } }; 29 30#define MAX_INPUT 2 31 32class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform { 33public: 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; 52private: 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/*************************************************************************/ 70int MyEffectRegister(ID2D1Factory1 *pD2Factory) { 71 return(MyEffect::Register(pD2Factory)); 72} 73 74/*************************************************************************/ 75/** Private code **/ 76/*************************************************************************/ 77MyEffect::MyEffect(void) { 78 Signature= SIGNATURE_MYEFFECT; 79 ctReference= 1; 80 ctInput= 0; 81 Zero(Constants); 82 Constants.tint[2]= 0.50f; 83} 84 85MyEffect::~MyEffect(void) { 86 Signature|= SIGNATURE_INVALID; 87} 88 89ULONG MyEffect::Release(void) { 90 if(--ctReference > 0) 91 return(ctReference); 92 delete this; 93 return(0); 94} 95 96HRESULT 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 126HRESULT 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 157HRESULT __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 166HRESULT 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. 193HRESULT MyEffect::SetGraph(ID2D1TransformGraph *pGraph) { 194 Warn(ERR_DIRECTX,"MyEffect:SetGraph: Should not be called."); 195 return(E_NOTIMPL); 196} 197 198HRESULT 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 206UINT32 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 215HRESULT 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 222HRESULT 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 231HRESULT 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 248IFACEMETHODIMP 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 266IFACEMETHODIMP 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 274IFACEMETHODIMP_(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.

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 8cbuffer constants: register(b0) { 9 float4 tint:COLOR; 10}; 11 12D2D_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.

Deploy.bat: 1REM %1 Execution directory $(SolutionDir)Test 2REM %2 Output directory $(OutDir) 3echo %1 %2 4copy /y "%2\FirstShader.cso" "%1"



WebV7 (C)2018 nlited | Rendered by tikope in 44.703ms | 18.117.170.130