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: /*************************************************************************/ /** Globals.h: Global declarations for PxlShader. **/ /** (C)2022 nlited systems, cmd **/ /*************************************************************************/ #pragma once #include <Windows.h> #include <d2d1_1.h> #include "StdTypes.h" #include "Handles.h" #include "Errors.h" #define SIGNATURE_PXLSHADER 0xCD190001 #define SIGNATURE_MYEFFECT 0xCD190002 #define SIGNATURE_MYTRANSFORM 0xCD190003 using namespace D2D1; typedef D2D1_POINT_2F POINT2D; EXTERNC const GUID CLSID_MyEffect; // {D8255497-025E-4D3F-A4DF-5C25306F67AC} #define SafeRelease(pInterface) { if(pInterface) pInterface->Release(); pInterface= 0; } // SafeRelease call Release() only if pInterface is nonzero. // pInterface is always set to zero, regardless the return value of Release(). // This is proper behavior because it is possible that some external process has // a reference that will be released at some future time, but as far as I am // concerned the interface has now ceased to exist. //Auto-destruct solid brush. class D2Brush { public: D2Brush(ID2D1RenderTarget *pRT, const D2D1_COLOR_F &clr) { pRT->CreateSolidColorBrush(clr,&pbrBrush); }; ~D2Brush(void) { pbrBrush->Release(); } operator ID2D1Brush *() { return(static_cast<ID2D1Brush*>(pbrBrush)); }; // This lets me use the object as the parameter to the various RenderTarget functions. ID2D1SolidColorBrush *pbrBrush; }; EXTERNC HINSTANCE ghInst; extern int PxlShaderCreate(HWND &hWnd); extern int MyEffectRegister(ID2D1Factory1 *pD2Factory); //EOF: GLOBALS.H

WinMain() is the app's entry point.

WinMain.cpp: /*************************************************************************/ /** WinMain.cpp: Windows entry point. **/ /** (C)2022 nlited systems, cmd **/ /*************************************************************************/ #include <Windows.h> #include "Handles.h" #include "ChipLib.h" #include "Globals.h" #pragma message(__FILE__": Optimizer disabled.") #pragma optimize("",off) HINSTANCE ghInst; DWORD DbgFilter; /*************************************************************************/ /** Window entry point **/ /*************************************************************************/ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pArgs, int nShow) { int Err= ERR_OK; HWND hWnd= 0; ghInst= hInst; MemCreate(); TmpBufCreate(16*1024*1024); if(IsErr(Err= PxlShaderCreate(hWnd))) { Err= Error(Err,"WinMain: Unable to create the main window."); } else { while(hWnd && IsWindow(hWnd)) { MSG Msg; GetMessage(&Msg,hWnd,0,0); TranslateMessage(&Msg); DispatchMessage(&Msg); } } TmpBufDestroy(); MemDestroy(); if(IsErr(MemReport())) MessageBox(0,L"PxlShader: Memory error.",L"PxlShader",MB_OK|MB_SETFOREGROUND); return(Err); } void ConsolePrint(DWORD Type, const WCHAR *Text) { TXT Out(0,0,"%s\r\n",Text); OutputDebugString(Out); } //EOF: WINMAIN.CPP

PxlShader.cpp contains all the code to manage and render the main window.

PxlShader.cpp: /*************************************************************************/ /** PxlShader.cpp: Minimal code to run a pixel shader. **/ /** (C)2022 nlited systems, cmd **/ /*************************************************************************/ #include <Windows.h> #include <d3d11_1.h> #include <d2d1_1.h> #include "Globals.h" #include "ChipLib.h" #pragma message(__FILE__": Optimizer disabled.") #pragma optimize("",off) static const WCHAR WndClassName[]= { L"PxlShader" }; class PxlShader { public: static PxlShader *Ptr(void *pObj); static PxlShader *Ptr(HWND hWnd); static int Create(HWND &hWnd); private: PxlShader(void); ~PxlShader(void); int Create2(void); static INT_PTR CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm); LRESULT WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm); int MsgCreate(HWND hWnd); int MsgDestroy(void); int MsgClose(void); int MsgTimer(void); int MsgMoved(void); int MsgPaint(void); int DrawCreate(void); int DrawCreateDX(void); int DrawCreateSwapChain(void); int DrawCreateD2Factory(void); int CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase); int CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite); int CreateEffect(void); int DrawUpdate(void); int DrawShow(void); void ReleaseEverything(void); //Data DWORD Signature; HWND hWnd; RECT rWnd; // Window client area POINT2D ptBall; // Bouncing ball position POINT2D BallVector; // Bouncing ball vector bool DoReset; // Call ReleaseEverything() before next draw. D3D_FEATURE_LEVEL DxFeatures; // Supported feature set IDXGIFactory2 *pDXGIFactory; // Creates SwapChain IDXGISwapChain1 *pSwapChain; // Final display and pDXGISurface IDXGISurface1 *pDXGISurface; // Used to create the bitmaps IDXGIDevice *pDXGIDevice; // Base display device ID2D1Factory1 *pD2Factory; // Creates Direct2D stuff ID2D1Device *pD2Device; // Spawns ID2D1DeviceContext ID2D1DeviceContext *pdcDraw; // The workhorse, used to draw everything. ID2D1Bitmap1 *pbmImg; // Final offscreen image (write-only) ID2D1Bitmap1 *pbmSrc1; // An intermediate offscreen image that can be composited. ID2D1Bitmap1 *pbmSrc2; // An intermediate offscreen image that can be composited. ID2D1Effect *pEffect; // Direct2D effect that contains my pixel shader. }; int PxlShaderCreate(HWND &hWnd) { return(PxlShader::Create(hWnd)); } /*************************************************************************/ /** PxlShader class **/ /*************************************************************************/ PxlShader::PxlShader(void) { Signature= SIGNATURE_PXLSHADER; ptBall= { 10,20 }; BallVector= { 1,1 }; } PxlShader::~PxlShader(void) { Signature|= SIGNATURE_INVALID; ReleaseEverything(); } PxlShader *PxlShader::Ptr(void *pObj) { PxlShader *pPxl= (PxlShader*)pObj; if(!pObj || IsBadPtr(pObj,sizeof(*pPxl),BADPTR_RW) || pPxl->Signature!=SIGNATURE_PXLSHADER) pPxl= 0; return(pPxl); } PxlShader *PxlShader::Ptr(HWND hWnd) { if(!hWnd || !IsWindow(hWnd)) return(0); return(Ptr((void*)GetWindowLongPtr(hWnd,GWLP_USERDATA))); } int PxlShader::Create(HWND &hWnd) { int Err= ERR_OK; PxlShader *pPxl= new PxlShader; if(!pPxl) { Err= Error(ERR_NO_MEM,"PxlShader:Create: NoMem"); } else if(IsErr(Err= pPxl->Create2())) { delete pPxl; } else { hWnd= pPxl->hWnd; } return(Err); } int PxlShader::Create2(void) { int Err= ERR_OK; ATOM hWndClass; WNDCLASS WndClass; RECT R= { 100,100,500,300 }; Zero(WndClass); WndClass.style= CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; WndClass.lpfnWndProc= WndProc; WndClass.hInstance= ghInst; WndClass.lpszClassName= WndClassName; DWORD style= WS_OVERLAPPEDWINDOW|WS_VISIBLE; if(!(hWndClass= RegisterClass(&WndClass))) { Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to register the main window class."); } else if(!(hWnd= CreateWindow(WndClassName,L"PxlShader",style,R.left,R.top,RWID(R),RHGT(R),0,0,ghInst,(LPVOID)this))) { Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to create the main window."); } return(Err); } /*************************************************************************/ /** Window message handler **/ /*************************************************************************/ INT_PTR CALLBACK PxlShader::WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) { INT_PTR Result= 0; PxlShader *pPxl= 0; if(Msg==WM_CREATE) { CREATESTRUCT *pCreate= (CREATESTRUCT*)lParm; pPxl= Ptr(pCreate->lpCreateParams); } else { pPxl= Ptr(hWnd); } if(!pPxl) { Result= DefWindowProc(hWnd,Msg,wParm,lParm); } else { Result= pPxl->WndProc2(hWnd,Msg,wParm,lParm); } return(Result); } LRESULT PxlShader::WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) { LRESULT Result= 0; switch(Msg) { case WM_CREATE: Result= MsgCreate(hWnd); break; case WM_DESTROY: Result= MsgDestroy(); break; case WM_CLOSE: Result= MsgClose(); break; case WM_TIMER: Result= MsgTimer(); break; case WM_WINDOWPOSCHANGED: Result= MsgMoved(); break; case WM_PAINT: Result= MsgPaint(); break; default: Result= DefWindowProc(hWnd,Msg,wParm,lParm); break; } return(Result); } int PxlShader::MsgCreate(HWND _hWnd) { hWnd= _hWnd; SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)this); SetTimer(hWnd,1,30,0); return(1); } int PxlShader::MsgDestroy(void) { SetWindowLongPtr(hWnd,GWLP_USERDATA,0); delete this; return(1); } int PxlShader::MsgClose(void) { DestroyWindow(hWnd); return(1); } int PxlShader::MsgTimer(void) { ptBall.x+= BallVector.x; if(ptBall.x < rWnd.left || ptBall.x >= rWnd.right) { BallVector.x= -BallVector.x; ptBall.x+= BallVector.x*2; } ptBall.y+= BallVector.y; if(ptBall.y < rWnd.top || ptBall.y >= rWnd.bottom) { BallVector.y= -BallVector.y; ptBall.y+= BallVector.y*2; } if(pEffect) { UINT32 Tint= ((UINT32)rand()<<16)|rand(); pEffect->SetValueByName(L"Tint",Tint); } InvalidateRect(hWnd,0,0); return(1); } int PxlShader::MsgMoved(void) { RECT rNew; GetClientRect(hWnd,&rNew); if(RWID(rNew)!=RWID(rWnd) || RHGT(rNew)!=RHGT(rWnd)) { rWnd= rNew; DoReset= true; } return(1); } int PxlShader::MsgPaint(void) { int Err= ERR_OK; PAINTSTRUCT Pnt; GetClientRect(hWnd,&rWnd); if(BeginPaint(hWnd,&Pnt)) { if(IsErr(Err= DrawCreate())) { Err= Warn(Err,"PxlShader:MsgPaint: DrawCreate() failed."); } else if(IsErr(Err= DrawUpdate())) { Err= Warn(Err,"PxlShader:MsgPaint: DrawUdpate() failed."); } else if(IsErr(Err= DrawShow())) { Err= Warn(Err,"PxlShader:MsgPaint: DrawPaint() failed."); } if(IsErr(Err)) { // Fall back to GDI paint. HBRUSH hbrFill= CreateSolidBrush(RGB(20,30,40)); FillRect(Pnt.hdc,&Pnt.rcPaint,hbrFill); DeleteObject(hbrFill); } EndPaint(hWnd,&Pnt); } ValidateRect(hWnd,0); return(1); } /*************************************************************************/ /** DirectX **/ /*************************************************************************/ int PxlShader::DrawCreate(void) { int Err= ERR_OK; HRESULT WinErr; D2D1_SIZE_U szWnd= { (UINT32)RWID(rWnd), (UINT32)RHGT(rWnd) }; D2D1_DEVICE_CONTEXT_OPTIONS DCOptions= D2D1_DEVICE_CONTEXT_OPTIONS_NONE; if(DoReset) ReleaseEverything(); if(!pDXGIDevice && IsErr(DrawCreateDX())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create DXGI device."); } else if(!pSwapChain && IsErr(Err= DrawCreateSwapChain())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create SwapChain."); } else if(!pDXGISurface && !SUCCEEDED(WinErr= pSwapChain->GetBuffer(0,IID_PPV_ARGS(&pDXGISurface)))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to retrieve DXGI surface. [%X]",WinErr); } else if(!pD2Factory && IsErr(Err= DrawCreateD2Factory())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D factory."); } else if(!pD2Device && !SUCCEEDED(WinErr= pD2Factory->CreateDevice(pDXGIDevice,&pD2Device))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D device."); } else if(!pdcDraw && !SUCCEEDED(WinErr= pD2Device->CreateDeviceContext(DCOptions,&pdcDraw))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Draw context."); } else if(!pbmImg && IsErr(Err= CreateBitmapBase(pdcDraw,szWnd,pbmImg))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create base bitmap."); } else if(!pEffect && IsErr(Err= CreateEffect())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create MyEffect."); } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); } return(Err); } int PxlShader::DrawCreateDX(void) { int Err= ERR_OK; HRESULT WinErr; UINT Flags= D3D11_CREATE_DEVICE_BGRA_SUPPORT; static const D3D_FEATURE_LEVEL Levels[]= { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; D3D_DRIVER_TYPE Type= D3D_DRIVER_TYPE_HARDWARE; UINT ctLevels= ARRAYSIZE(Levels); UINT Version= D3D11_SDK_VERSION; ID3D11Device *pD3D11Device= 0; ID3D11DeviceContext *pD3D11DC= 0; IDXGIAdapter *pDXGIAdapter= 0; if(!SUCCEEDED(WinErr= D3D11CreateDevice(0,Type,0,Flags,Levels,ctLevels,Version,&pD3D11Device,&DxFeatures,&pD3D11DC))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: D3D11CreateDevice() failed."); } else if(!SUCCEEDED(WinErr= pD3D11Device->QueryInterface(&pDXGIDevice))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI device. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pDXGIDevice->GetAdapter(&pDXGIAdapter))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI adapter. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pDXGIAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory)))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI factory. [%X]",WinErr); } //NOTE: pDXGIDevice has a RefCt of 3! SafeRelease(pDXGIAdapter); SafeRelease(pD3D11Device); SafeRelease(pD3D11DC); return(Err); } int PxlShader::DrawCreateSwapChain(void) { int Err= ERR_OK; HRESULT WinErr; DXGI_SWAP_CHAIN_DESC1 SwapDesc; Zero(SwapDesc); SwapDesc.Format= DXGI_FORMAT_B8G8R8A8_UNORM; SwapDesc.SampleDesc.Count= 1; SwapDesc.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT; SwapDesc.BufferCount= 2; SwapDesc.Scaling= DXGI_SCALING_STRETCH; SwapDesc.SwapEffect= DXGI_SWAP_EFFECT_DISCARD; if(!SUCCEEDED(WinErr= pDXGIFactory->CreateSwapChainForHwnd(pDXGIDevice,hWnd,&SwapDesc,0,0,&pSwapChain))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateSwapChain: Unable to create SwapChain. [%X]",WinErr); } return(Err); } int PxlShader::DrawCreateD2Factory(void) { int Err= ERR_OK; HRESULT WinErr; REFIID guid= __uuidof(ID2D1Factory1); D2D1_FACTORY_OPTIONS options; options.debugLevel= D2D1_DEBUG_LEVEL_INFORMATION; // DEBUG_LEVEL will trigger exceptions if EndDraw() fails or the factory is released with // outstanding (unreleased) objects. if(!SUCCEEDED(WinErr= D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,guid,&options,(void**)&pD2Factory))) { Err= Error(ERR_DIRECTX,"PxlShader:DrawCreateD2Factory: Unable to create D2D factory. [%X]",WinErr); } return(Err); } // Create a targetable bitmap from a DXGI surface. // This serves as the final rendering destination bitmap. int PxlShader::CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase) { int Err= ERR_OK; HRESULT WinErr; IDXGISurface *pSurface= 0; D2D1_BITMAP_PROPERTIES1 bmProp; Zero(bmProp); bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET|D2D1_BITMAP_OPTIONS_CANNOT_DRAW; bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_IGNORE); pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY); if(!SUCCEEDED(WinErr= pdcDst->CreateBitmapFromDxgiSurface(pDXGISurface,bmProp,&pbmBase))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapBase: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height); } else { pdcDst->SetTarget(pbmBase); } return(Err); } // Create a targetable bitmap that can be used for compositing. int PxlShader::CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite) { int Err= ERR_OK; HRESULT WinErr; D2D1_BITMAP_PROPERTIES1 bmProp; Zero(bmProp); bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET; bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED); pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY); if(!SUCCEEDED(WinErr= pdcDst->CreateBitmap(szBitmap,0,0,bmProp,&pbmComposite))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapComposite: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height); } else { pdcDst->SetTarget(pbmComposite); } return(Err); } int PxlShader::CreateEffect(void) { int Err= ERR_OK; HRESULT WinErr; if(IsErr(Err= MyEffectRegister(pD2Factory))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to register MyEffect."); } else if(!SUCCEEDED(WinErr= pdcDraw->CreateEffect(CLSID_MyEffect,&pEffect))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to create MyEffect. [%X]",WinErr); } else { Print(PRINT_INFO,"PxlShader:CreateEffect: OK"); } return(Err); } void PxlShader::ReleaseEverything(void) { SafeRelease(pEffect); SafeRelease(pbmSrc2); SafeRelease(pbmSrc1); SafeRelease(pbmImg); SafeRelease(pdcDraw); SafeRelease(pD2Device); SafeRelease(pD2Factory); SafeRelease(pDXGISurface); SafeRelease(pSwapChain); SafeRelease(pDXGIFactory); SafeRelease(pDXGIDevice); DoReset= false; } /*************************************************************************/ /** Draw **/ /*************************************************************************/ int PxlShader::DrawUpdate(void) { int Err= ERR_OK; HRESULT WinErr; if(!pdcDraw || !pbmImg || !pbmSrc1 || !pbmSrc2 || !pEffect) { Err= Warn(ERR_NOT_CREATED,"PxlShader:DrawUpdate: No resources."); } else { pdcDraw->BeginDraw(); pdcDraw->SetTransform(Matrix3x2F::Identity()); pdcDraw->SetTarget(pbmSrc1); pdcDraw->Clear(ColorF(ColorF::Black,0)); D2D1_RECT_F box= { 0,0,80,60 }; pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod))); pdcDraw->SetTarget(pbmSrc2); pdcDraw->Clear(ColorF(ColorF::Black,0)); D2D1_ELLIPSE dot= { {50,50}, 50,50 }; pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen))); pdcDraw->SetTarget(pbmImg); pdcDraw->Clear(ColorF(ColorF::Black,0)); pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y))); pEffect->SetInput(0,pbmSrc1); pEffect->SetInput(1,pbmSrc2); pdcDraw->DrawImage(pEffect); if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) { Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr); DoReset= true; } } return(Err); } int PxlShader::DrawShow(void) { int Err= ERR_OK; HRESULT WinErr; DXGI_PRESENT_PARAMETERS PresentParm; Zero(PresentParm); if(!pSwapChain) { Err= Warn(ERR_NOT_CREATED,"PxlShader:DrawShow: No SwapChain."); } else if(!SUCCEEDED(WinErr= pSwapChain->Present1(1,0,&PresentParm))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawShow: Present() failed. [%X]",WinErr); DoReset= true; } return(Err); } //EOF: PXLSHADER.CPP

MyEffect.cpp contains all the code to implement my custom Direct2D Effect.

MyEffect.cpp: /*************************************************************************/ /** MyEffect.cpp: A simple pixel shader wrapped inside ID2D1Effect. **/ /** (C)2022 nlited systems, cmd **/ /*************************************************************************/ #include <Windows.h> #include <d3d11_1.h> #include <d2d1.h> #include <d2d1_1.h> #include <d2d1helper.h> #include <d2d1effectauthor.h> #include <d2d1effecthelpers.h> #include <d3dcompiler.h> #include "Globals.h" #include "ChipLib.h" #pragma comment(lib,"D3D11.lib") #pragma comment(lib,"D2D1.lib") #pragma comment(lib,"DXGI.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma message(__FILE__": Optimizer disabled.") #pragma optimize("",off) // {D8255497-025E-4D3F-A4DF-5C25306F67AC} const GUID CLSID_MyEffect = { 0xd8255497, 0x25e, 0x4d3f, { 0xa4, 0xdf, 0x5c, 0x25, 0x30, 0x6f, 0x67, 0xac } }; // {2BCB702A-4F42-44D0-B8ED-4E9F9FC7A905} static const GUID GUID_MyPixelShader = { 0x2bcb702a, 0x4f42, 0x44d0, { 0xb8, 0xed, 0x4e, 0x9f, 0x9f, 0xc7, 0xa9, 0x5 } }; #define MAX_INPUT 2 class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform { public: //EffectImpl static HRESULT Register(_In_ ID2D1Factory1 *pFactory); static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect); IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface); IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); }; IFACEMETHODIMP_(ULONG) Release(void); IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph); IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type); IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph); //DrawTransform IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw); IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const; IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque); IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const; IFACEMETHODIMP_(UINT32) GetInputCount(void) const; //Added HRESULT SetTint(UINT32 Clr); UINT32 GetTint(void) const; private: MyEffect(void); ~MyEffect(void); // Data DWORD Signature; LONG ctReference; ID2D1EffectContext *pCtx; ID2D1DrawInfo *pDraw; UINT ctInput; D2D1_RECT_L rIn[MAX_INPUT]; struct ShaderConstant_s { float tint[4]; } Constants; }; /*************************************************************************/ /** Public interface **/ /*************************************************************************/ int MyEffectRegister(ID2D1Factory1 *pD2Factory) { return(MyEffect::Register(pD2Factory)); } /*************************************************************************/ /** Private code **/ /*************************************************************************/ MyEffect::MyEffect(void) { Signature= SIGNATURE_MYEFFECT; ctReference= 1; ctInput= 0; Zero(Constants); Constants.tint[2]= 0.50f; } MyEffect::~MyEffect(void) { Signature|= SIGNATURE_INVALID; } ULONG MyEffect::Release(void) { if(--ctReference > 0) return(ctReference); delete this; return(0); } HRESULT MyEffect::QueryInterface(REFIID riid, void **ppInterface) { HRESULT WinErr= S_OK; void *pInterface= 0; if(riid==__uuidof(ID2D1EffectImpl)) { pInterface= reinterpret_cast<ID2D1EffectImpl*>(this); } else if(riid==__uuidof(ID2D1DrawTransform)) { pInterface= static_cast<ID2D1DrawTransform*>(this); } else if(riid==__uuidof(ID2D1Transform)) { pInterface= static_cast<ID2D1Transform*>(this); } else if(riid==__uuidof(ID2D1TransformNode)) { pInterface= static_cast<ID2D1TransformNode*>(this); } else if(riid==__uuidof(ID2D1ComputeTransform)) { Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a compute transform."); WinErr= E_NOINTERFACE; } else if(riid==__uuidof(ID2D1SourceTransform)) { Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a source transform."); WinErr= E_NOINTERFACE; } else if(riid==__uuidof(IUnknown)) { pInterface= this; } else { WinErr= E_NOINTERFACE; } if(ppInterface) { *ppInterface= pInterface; if(pInterface) AddRef(); } return(WinErr); } HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) { HRESULT WinErr= S_OK; static const PCWSTR pszXml = L"<?xml version='1.0'?>\r\n" L"<Effect>\r\n" L" <!-- System Properties -->\r\n" L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n" L" <Property name='Author' type='string' value='nlited systems'/>\r\n" L" <Property name='Category' type='string' value='Experimental'/>\r\n" L" <Property name='Description' type='string' value='My first effect.'/>\r\n" L" <Inputs minimum='0' maximum='2'>\r\n" // Source must be specified. L" <Input name='Source1'/>\r\n" L" <Input name='Source2'/>\r\n" L" </Inputs>\r\n" L" <!-- Custom Properties go here. -->\r\n" L" <Property name='Tint' type='uint32'>\r\n" L" <Property name='DisplayName' type='string' value='Tint'/>\r\n" L" <Property name='Default' type='uint32' value='0'/>\r\n" L" </Property>\r\n" L"</Effect>\r\n" ; static const D2D1_PROPERTY_BINDING Bindings[]= { D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint) }; if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) { Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr); } return(WinErr); } HRESULT __stdcall MyEffect::CreateMyEffect(IUnknown **ppEffect) { HRESULT WinErr= S_OK; *ppEffect= static_cast<ID2D1EffectImpl*>(new MyEffect); if(!*ppEffect) { WinErr= E_OUTOFMEMORY; } return(WinErr); } HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) { HRESULT WinErr= S_OK; ID3DBlob *pCode= 0; ID3DBlob *pError= 0; pCtx= _pCtx; if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"FirstShader.cso",&pCode))) { Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr); } else { ctInput= 2; Print(PRINT_INFO,"MyEffect:Initialize: OK."); } SafeRelease(pCode); SafeRelease(pError); return(WinErr); } // This is a single-transform, single-node graph, SetGraph() should never be called. HRESULT MyEffect::SetGraph(ID2D1TransformGraph *pGraph) { Warn(ERR_DIRECTX,"MyEffect:SetGraph: Should not be called."); return(E_NOTIMPL); } HRESULT MyEffect::SetTint(UINT32 Clr) { Constants.tint[0]= (float)((Clr>>16) & 0xFF)/255.0f; Constants.tint[1]= (float)((Clr>> 8) & 0xFF)/255.0f; Constants.tint[2]= (float)((Clr ) & 0xFF)/255.0f; Constants.tint[3]= (float)((Clr>>24) & 0xFF)/255.0f; return(S_OK); } UINT32 MyEffect::GetTint(void) const { UINT32 Clr= 0; Clr|= ((UINT32)(Constants.tint[0]*255.0f) & 0xFF)<<16; Clr|= ((UINT32)(Constants.tint[1]*255.0f) & 0xFF)<< 8; Clr|= ((UINT32)(Constants.tint[2]*255.0f) & 0xFF); Clr|= ((UINT32)(Constants.tint[3]*255.0f) & 0xFF)<<24; return(Clr); } HRESULT MyEffect::PrepareForRender(D2D1_CHANGE_TYPE Type) { HRESULT WinErr= S_OK; pDraw->SetPixelShaderConstantBuffer((BYTE*)&Constants,sizeof(Constants)); return(WinErr); } // ID2D1DrawTransform HRESULT MyEffect::SetDrawInfo(ID2D1DrawInfo *_pDraw) { HRESULT WinErr= S_OK; pDraw= _pDraw; if(!SUCCEEDED(WinErr= pDraw->SetPixelShader(GUID_MyPixelShader))) { Warn(ERR_DIRECTX,"MyEffect:SetDrawInfo: SetPixelShader() failed. [%X]",WinErr); } return(WinErr); } HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const { HRESULT WinErr= S_OK; //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn); if(ctIn==0) { Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?"); } else if(ctIn>MAX_INPUT) { Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn); WinErr= E_INVALIDARG; } else if(ctIn>0) { prIn[0]= *prOut; for(UINT n1=1;n1<ctIn;n1++) { prIn[n1]= *prOut; } } return(WinErr); } IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) { HRESULT WinErr= S_OK; //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn); if(ctIn==0) { Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?"); } else if(ctIn>MAX_INPUT) { Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn); WinErr= E_INVALIDARG; } else if(ctIn>0) { *prOut= rIn[0]= prIn[0]; for(UINT n1=1;n1<ctIn;n1++) { rIn[n1]= prIn[n1]; } Zero(*prOutOpaque); } return(WinErr); } IFACEMETHODIMP MyEffect::MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOutInvalid) const { HRESULT WinErr= S_OK; Print(PRINT_DEBUG,"MyEffect:MapInvalidRect:"); // Set entire output to invalid *prOutInvalid= rIn[0]; return(WinErr); } IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const { return(MAX_INPUT); } //EOF: MYEFFECT.CPP

FirstShader.hlsl contains the pixel shader code that will run on the GPU.

FirstShader.hlsl: /*************************************************************************/ /** FirstShader.hlsl: My First Pixel Shader. **/ /** (C)2022 nlited systems, cmd **/ /*************************************************************************/ #define D2D_INPUT_COUNT 2 #include "d2d1effecthelpers.hlsli" cbuffer constants: register(b0) { float4 tint:COLOR; }; D2D_PS_ENTRY(main) { float4 color= 0; float4 color0= D2DGetInput(0); float4 color1= D2DGetInput(1); if(color0.a && color1.a) { color= (color0+color1*2)/3; } else if(color0.a) { color= (color0+tint)/2; } else if(color1.a) { color= (color1+tint)/2; } return color; } //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: REM %1 Execution directory $(SolutionDir)Test REM %2 Output directory $(OutDir) echo %1 %2 copy /y "%2\FirstShader.cso" "%1"

Moderator: close comments Comments are closed.

Comments are moderated. Anonymous comments are not visible to others until moderated. Comments are owned by the author but may be removed or reused (but not modified) by this site at any time without notice.

HTML
  1. Moderator: [] approve delete HTML



WebV7 (C)2018 nlited | Rendered by tikope in 39.323ms | 3.15.218.234