dev.nlited.com

>>

Multiple Sources

<<<< prev
next >>>>

2022-12-16 16:39:09 chip Page 2468 📢 PUBLIC

December 15 2022

So far everything has taken a single input, twiddled the pixels, and output pixels 1:1. Now I want to merge multiple sources into a single output. This is the final requirement for my Fog of War effect.

Figuring this out took a while ...

Adding a second source to the XML descriptor still works, so the second source is optional.

I have several questions:

1635: I have spent about four hours trying to add a second input. There are no errors, but all I see are black pixels. I'm not sure if D2DGetInput(1) is failing to read the pixels on the GPU or if pEffect->SetInput(1,pbmSrc2) is failing to add the second source.

1900: Signs of hope? I did something, not sure what, that caused SetGraph() to be called. I believe this is a signal that the second input is being connected. But still no second source appearing in the output. Going to sleep on it.

December 16 2022

I am going to carve ID2D1DrawTransform out of MyEffect into its own stand-alone class, on the hunch that maybe I need multiple transforms.

After an hour or so, MyEffect is "working" again with an external MyTransform. "Working" means I see only one input, but it runs.

I am beginning to suspect the call to SetSingleTransformNode() ... I replaced this with the sequence AddNode(), SetOutputNode(), ConnectToEffectInput(), ConnectToEffectInput().

Progress! I am now seeing all of Source1 and part of Source2! I suspect this may have something to do with the Map...Rect() functions.

0900: SUCCESS!!! I needed to copy all the rectangles, I was only copying the first one. I now see the merged output of both inputs!

PxlShader

I suspect carving out the DrawTransform was not necessary after all, and having them separate causes some awkward code in PrepareForRender(). (The Effect has the constant parameters, but the Transform has the interface to transfer the constants to the shader. The forced me to create a way to have MyEffect::PrepareForRender() call MyTransform to perform the transfer.) I am going to spend a few minutes undoing that carve out and see if everything still works.

0930: That was quick. Using a merged ID2D1EffectImpl / ID2D1DrawTransform works, now that I know how to assemble the graph properly. Now I can go back and try to document the changes...

Adding a Second Input

My effect is going to take two sources and output the average pixel. Going from a single source to two is a big change, but going from two to three or more should just be a matter of changing MAX_INPUT. I read somewhere that shaders have an upper limit of 8 inputs. (Not sure about that number.)

My effect will still be a single transform, so I can continue to merge both ID2D1EffectImpl and ID2D1DrawTransform into a single class. Each input will have its own input rectangle. The only change to the MyEffect class declaration is setting a limit for the number of inputs and converting rIn to an array.


MyEffect declaration: 1#define MAX_INPUT 2 2 3class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform { 4public: 5 //EffectImpl 6 static HRESULT Register(_In_ ID2D1Factory1 *pFactory); 7 static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect); 8 IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface); 9 IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); }; 10 IFACEMETHODIMP_(ULONG) Release(void); 11 IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph); 12 IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type); 13 IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph); 14 //DrawTransform 15 IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw); 16 IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const; 17 IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque); 18 IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const; 19 IFACEMETHODIMP_(UINT32) GetInputCount(void) const; 20 //Added 21 HRESULT SetTint(UINT32 Clr); 22 UINT32 GetTint(void) const; 23private: 24 MyEffect(void); 25 ~MyEffect(void); 26 // Data 27 DWORD Signature; 28 LONG ctReference; 29 ID2D1EffectContext *pCtx; 30 ID2D1DrawInfo *pDraw; 31 UINT ctInput; 32 D2D1_RECT_L rIn[MAX_INPUT]; 33 struct ShaderConstant_s { 34 float tint[4]; 35 } Constants; 36};

The XML description of the effect in Register() needs to change to allow two inputs. Note that both Inputs:maximum and the number of Input clauses need to match.

MyEffect::Register(): 1HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) { 2 HRESULT WinErr= S_OK; 3 static const PCWSTR pszXml = 4 L"<?xml version='1.0'?>\r\n" 5 L"<Effect>\r\n" 6 L" <!-- System Properties -->\r\n" 7 L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n" 8 L" <Property name='Author' type='string' value='nlited systems'/>\r\n" 9 L" <Property name='Category' type='string' value='Experimental'/>\r\n" 10 L" <Property name='Description' type='string' value='My first effect.'/>\r\n" 11 L" <Inputs minimum='0' maximum='2'>\r\n" 12 // Source must be specified. 13 L" <Input name='Source1'/>\r\n" 14 L" <Input name='Source2'/>\r\n" 15 L" </Inputs>\r\n" 16 L" <!-- Custom Properties go here. -->\r\n" 17 L" <Property name='Tint' type='uint32'>\r\n" 18 L" <Property name='DisplayName' type='string' value='Tint'/>\r\n" 19 L" <Property name='Default' type='uint32' value='0'/>\r\n" 20 L" </Property>\r\n" 21 L"</Effect>\r\n" 22 ; 23 static const D2D1_PROPERTY_BINDING Bindings[]= { 24 D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint) 25 }; 26 if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) { 27 Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr); 28 } 29 return(WinErr); 30}

Initialize() needs to change, I can no longer call SetSingleTransformNode(). This confused me for a long time, I thought it should be ok to set additional inputs after creating the single node. It seems I cannot make any changes after calling SetSingleTransformNode(). Multiple inputs requires configuring the graph manually instead. I was further confused by the somewhat terse and ambiguous description of ConnectToEffectInput(). Being able to specify both the EffectInput and the NodeInput allows me to cross-wire the inputs, but the typical usage is to connect them directly; ie use EffectInput == NodeInput. I need to call for each input, 0 and 1.

MyEffect::Initialize(): 1HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) { 2 HRESULT WinErr= S_OK; 3 ID3DBlob *pCode= 0; 4 ID3DBlob *pError= 0; 5 pCtx= _pCtx; 6 if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"S:\\Src\\HQ\\Dev\\SB\\Chip\\Bugs\\BugsV1\\Out\\Winx64Debug\\FirstShader.cso",&pCode))) { 7 Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr); 8 } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) { 9 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr); 10 } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) { 11 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr); 12 } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) { 13 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr); 14 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) { 15 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr); 16 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) { 17 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr); 18 } else { 19 ctInput= 2; 20 Print(PRINT_INFO,"MyEffect:Initialize: OK."); 21 } 22 SafeRelease(pCode); 23 SafeRelease(pError); 24 return(WinErr); 25}

Note: This all happens in Initialize(), not in response to the app calling pEffect->SetInput() as I originally expected. There is a bit of a disconnect here, because MyEffect has to assume there are always 2 inputs. There is no notification when the app sets them. In fact, if the app fails to connect the second input MyEffect will never know, but the pdcDraw->EndDraw() will fail with a mysterious "0x8899001E: There was a configuration error in the graph." This behavior is unfortunate because it means I cannot be flexible in the number of inputs MyEffect will accept. If I want to average 2 or 3 sources, I have to create two dedicated effects, one that handles 2 sources and another to handle 3. GetInputCount() must return 2 in one case and 3 in the other. And if the app supplies only 2 sources for the 3-source effect, the Draw() will fail. (pEffect->SetInputCount() seems to be completely feckless.)

SetGraph() is still never called. I believe it is only called if another transform node is added to the graph. MyEffect is still a single transform, just now with multiple inputs.

PrepareForRender() and SetDrawInfo() remain the same. When I carved out the ID2D1DrawTransform into its own class, I ran into a bit of a Catch-22 here: ID2D1EffectImpl::PrepareForRender() is the prompt to transfer the constant parameters to the shader, but ID2D1DrawTransform::SetDrawInfo() is provided the ID2D1DrawInfo interface needed to perform the transfer. This required creating a duplicate MyTransform::PrepareForRender() that is called from MyEffect::PrepareForRender(). This seemed a bit silly and was another point in favor of keeping MyEffect as an amalgam of both ID2D1EffectImpl and ID2D1DrawTransform.

MapOutputRectToInputRects() and MapInputRectsToOutputRect() now need to handle multiple input rectangles. This became obvious when I finally sorted out the graph creation in Initialize() and saw the second source was being truncated. I am still not 100% clear on exactly what these functions are really supposed to do, but copying the rectangles seems to work.

This may work only because both pbmSrc1 and pbmSrc2 happen to be the same size.

MyEffect::MapRects: 1HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const { 2 HRESULT WinErr= S_OK; 3 //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn); 4 if(ctIn==0) { 5 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?"); 6 } else if(ctIn>MAX_INPUT) { 7 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn); 8 WinErr= E_INVALIDARG; 9 } else if(ctIn>0) { 10 prIn[0]= *prOut; 11 for(UINT n1=1;n1<ctIn;n1++) { 12 prIn[n1]= *prOut; 13 } 14 } 15 return(WinErr); 16} 17 18IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) { 19 HRESULT WinErr= S_OK; 20 //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn); 21 if(ctIn==0) { 22 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?"); 23 } else if(ctIn>MAX_INPUT) { 24 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn); 25 WinErr= E_INVALIDARG; 26 } else if(ctIn>0) { 27 *prOut= rIn[0]= prIn[0]; 28 for(UINT n1=1;n1<ctIn;n1++) { 29 rIn[n1]= prIn[n1]; 30 } 31 Zero(*prOutOpaque); 32 } 33 return(WinErr); 34}

MapInvalidRect() remains the same.

GetInputCount() needs to return the expected number of inputs, not the number currently connected.

MyEffect::GetInputCount(): 1IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const { 2 return(MAX_INPUT); 3}

MyEffect now supports (and expects) MAX_INPUT (2) inputs.

My app needs to provide two sources, not just one. PxlShader::DrawCreate() needs to create two source bitmaps, pbmSrc1 and pbmSrc2.

PxlShader declaration: 1class PxlShader { 2 ... 3private: 4 ... 5 ID2D1Bitmap1 *pbmSrc1; 6 ID2D1Bitmap1 *pbmSrc2; 7}; 8 9int PxlShader::DrawCreate(void) { 10 ... 11 } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) { 12 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); 13 } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) { 14 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); 15 } 16 return(Err); 17}

And DrawUpdate() continues to become ever more complex. Now I need to draw unique shapes into the two source bitmaps, something I can easily recognize. pbmSrc1 will contain a goldenrod rectangle, pbmSrc2 a forest green circle, and they should partially overlap in the merged output. pbmSrc2 is added as the second input to the effect.

PxlShader::DrawUpdate(): 1int PxlShader::DrawUpdate(void) { 2 int Err= ERR_OK; 3 HRESULT WinErr; 4 pdcDraw->BeginDraw(); 5 pdcDraw->SetTransform(Matrix3x2F::Identity()); 6 pdcDraw->SetTarget(pbmSrc1); 7 pdcDraw->Clear(ColorF(ColorF::Black,0)); 8 D2D1_RECT_F box= { 0,0,80,60 }; 9 pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod))); 10 pdcDraw->SetTarget(pbmSrc2); 11 pdcDraw->Clear(ColorF(ColorF::Black,0)); 12 D2D1_ELLIPSE dot= { {50,50}, 50,50 }; 13 pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen))); 14 pdcDraw->SetTarget(pbmImg); 15 pdcDraw->Clear(ColorF(ColorF::Black,0)); 16 pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y))); 17 pEffect->SetInput(0,pbmSrc1); 18 pEffect->SetInput(1,pbmSrc2); 19 pdcDraw->DrawImage(pEffect); 20 if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) { 21 Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr); 22 ReleaseEverything(); 23 } 24 return(Err); 25}

At one point I was calling pEffect->SetInputCount(2) but this seemed to have no effect whatsoever.

And finally the shader. I need to have it do something that will make both inputs obvious in the output: An average of the two pixels.

FirstShader.hlsl: 1#define D2D_INPUT_COUNT 2 2#include "d2d1effecthelpers.hlsli" 3 4cbuffer constants: register(b0) { 5 float4 tint:COLOR; 6}; 7 8D2D_PS_ENTRY(main) { 9 float4 color; 10 float4 color0= D2DGetInput(0); 11 float4 color1= D2DGetInput(1); 12 color= (color0+color1)/2; 13 return color; 14} 15 16 //EOF: FIRSTSHADER.HLSL

D2DGetInput(n) will retrieve the current pixel from input #n. If there is no input #n, it will return a black pixel without any error. This led to a lot of confusion about whether the input was missing or the shader was failing to access it. Not knowing the difference wasted a couple hours yesterday.

Now I should see both the goldenrod box and the green circle, with the overlap being some sort of yellowish-green.

PxlShader

The non-overlap regions are dark because I am averaging in the black pixels. I can fix that...

Shader2: 1#define D2D_INPUT_COUNT 2 2#include "d2d1effecthelpers.hlsli" 3 4cbuffer constants: register(b0) { 5 float4 tint:COLOR; 6}; 7 8D2D_PS_ENTRY(main) { 9 float4 color; 10 float4 color0= D2DGetInput(0); 11 float4 color1= D2DGetInput(1); 12 if(color0.a==0) { 13 color= color1; 14 } else if(color1.a==0) { 15 color= color0; 16 } else { 17 color= (color0+color1)/2; 18 } 19 return color; 20} 21 22 //EOF: FIRSTSHADER.HLSL

PxlShader

Success! I now know how to merge two source bitmaps into a single output image.

The complete PxlShader app:

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.h> 8#include <d2d1_1.h> 9#include <d2d1helper.h> 10#include <d2d1effectauthor.h> 11#include <d2d1effecthelpers.h> 12#include <d3dcompiler.h> 13#include "Handles.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#define SIGNATURE_PXLSHADER 0xCD190001 25#define SIGNATURE_MYEFFECT 0xCD190002 26#define SIGNATURE_MYTRANSFORM 0xCD190003 27 28using namespace D2D1; 29typedef D2D1_POINT_2F POINT2D; 30 31HINSTANCE ghInst; 32DWORD DbgFilter; 33static const WCHAR ClassName[]= { L"PxlShader" }; 34 35 // {D8255497-025E-4D3F-A4DF-5C25306F67AC} 36static const GUID CLSID_MyEffect = { 0xd8255497, 0x25e, 0x4d3f, { 0xa4, 0xdf, 0x5c, 0x25, 0x30, 0x6f, 0x67, 0xac } }; 37 38 // {2BCB702A-4F42-44D0-B8ED-4E9F9FC7A905} 39static const GUID GUID_MyPixelShader = { 0x2bcb702a, 0x4f42, 0x44d0, { 0xb8, 0xed, 0x4e, 0x9f, 0x9f, 0xc7, 0xa9, 0x5 } }; 40 41#define SafeRelease(pInterface) { if(pInterface && pInterface->Release()==0) pInterface= 0; } 42 43 //Auto-destruct solid brush. 44class D2Brush { 45public: 46 D2Brush(ID2D1RenderTarget *pRT, const D2D1_COLOR_F &clr) { 47 pRT->CreateSolidColorBrush(clr,&pbrBrush); 48 }; 49 ~D2Brush(void) { 50 pbrBrush->Release(); 51 } 52 operator ID2D1Brush *() { return(static_cast<ID2D1Brush*>(pbrBrush)); }; 53 // This lets me use the object as the parameter to the various RenderTarget functions. 54 ID2D1SolidColorBrush *pbrBrush; 55}; 56 57#define MAX_INPUT 2 58 59class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform { 60public: 61 //EffectImpl 62 static HRESULT Register(_In_ ID2D1Factory1 *pFactory); 63 static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect); 64 IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface); 65 IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); }; 66 IFACEMETHODIMP_(ULONG) Release(void); 67 IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph); 68 IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type); 69 IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph); 70 //DrawTransform 71 IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw); 72 IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const; 73 IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque); 74 IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const; 75 IFACEMETHODIMP_(UINT32) GetInputCount(void) const; 76 //Added 77 HRESULT SetTint(UINT32 Clr); 78 UINT32 GetTint(void) const; 79private: 80 MyEffect(void); 81 ~MyEffect(void); 82 // Data 83 DWORD Signature; 84 LONG ctReference; 85 ID2D1EffectContext *pCtx; 86 ID2D1DrawInfo *pDraw; 87 UINT ctInput; 88 D2D1_RECT_L rIn[MAX_INPUT]; 89 struct ShaderConstant_s { 90 float tint[4]; 91 } Constants; 92}; 93 94class PxlShader { 95public: 96 static PxlShader *Ptr(void *pObj); 97 static PxlShader *Ptr(HWND hWnd); 98 static int Create(HWND &hWnd); 99private: 100 PxlShader(void); 101 ~PxlShader(void); 102 int Create2(void); 103 static INT_PTR CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm); 104 LRESULT WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm); 105 int MsgCreate(HWND hWnd); 106 int MsgDestroy(void); 107 int MsgClose(void); 108 int MsgTimer(void); 109 int MsgMoved(void); 110 int MsgPaint(void); 111 int DrawCreate(void); 112 int DrawCreateDX(void); 113 int DrawCreateSwapChain(void); 114 int DrawCreateD2Factory(void); 115 int CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase); 116 int CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite); 117 int CreateEffect(void); 118 int DrawUpdate(void); 119 int DrawShow(void); 120 void ReleaseEverything(void); 121 //Data 122 DWORD Signature; 123 HWND hWnd; 124 RECT rWnd; // Window client area 125 POINT2D ptBall; // Bouncing ball position 126 POINT2D BallVector; // Bouncing ball vector 127 D3D_FEATURE_LEVEL DxFeatures; // Supported feature set 128 IDXGIFactory2 *pDXGIFactory; 129 IDXGISwapChain1 *pSwapChain; 130 IDXGISurface1 *pDXGISurface; 131 IDXGIDevice *pDXGIDevice; 132 ID2D1Factory1 *pD2Factory; 133 ID2D1Device *pD2Device; 134 ID2D1DeviceContext *pdcDraw; 135 ID2D1Bitmap1 *pbmImg; 136 ID2D1Bitmap1 *pbmSrc1; 137 ID2D1Bitmap1 *pbmSrc2; 138 ID2D1Effect *pEffect; 139}; 140 141/*************************************************************************/ 142/** Window entry point **/ 143/*************************************************************************/ 144int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pArgs, int nShow) { 145 int Err= ERR_OK; 146 HWND hWnd= 0; 147 ghInst= hInst; 148 MemCreate(); 149 TmpBufCreate(16*1024*1024); 150 if(IsErr(Err= PxlShader::Create(hWnd))) { 151 Err= Error(Err,"WinMain: Unable to create the main window."); 152 } else { 153 while(hWnd && IsWindow(hWnd)) { 154 MSG Msg; 155 GetMessage(&Msg,hWnd,0,0); 156 TranslateMessage(&Msg); 157 DispatchMessage(&Msg); 158 } 159 } 160 TmpBufDestroy(); 161 MemDestroy(); 162 if(IsErr(MemReport())) 163 MessageBox(0,L"PxlShader: Memory error.",L"PxlShader",MB_OK|MB_SETFOREGROUND); 164 return(Err); 165} 166 167void ConsolePrint(DWORD Type, const WCHAR *Text) { 168 TXT Out(0,0,"%s\r\n",Text); 169 OutputDebugString(Out); 170} 171 172/*************************************************************************/ 173/** PxlShader class **/ 174/*************************************************************************/ 175PxlShader::PxlShader(void) { 176 Signature= SIGNATURE_PXLSHADER; 177 ptBall= { 10,20 }; 178 BallVector= { 1,1 }; 179} 180 181PxlShader::~PxlShader(void) { 182 Signature|= SIGNATURE_INVALID; 183 ReleaseEverything(); 184} 185 186PxlShader *PxlShader::Ptr(void *pObj) { 187 PxlShader *pPxl= (PxlShader*)pObj; 188 if(!pObj || IsBadPtr(pObj,sizeof(*pPxl),BADPTR_RW) || pPxl->Signature!=SIGNATURE_PXLSHADER) 189 pPxl= 0; 190 return(pPxl); 191} 192 193PxlShader *PxlShader::Ptr(HWND hWnd) { 194 if(!hWnd || !IsWindow(hWnd)) 195 return(0); 196 return(Ptr((void*)GetWindowLongPtr(hWnd,GWLP_USERDATA))); 197} 198 199int PxlShader::Create(HWND &hWnd) { 200 int Err= ERR_OK; 201 PxlShader *pPxl= new PxlShader; 202 if(!pPxl) { 203 Err= Error(ERR_NO_MEM,"PxlShader:Create: NoMem"); 204 } else if(IsErr(Err= pPxl->Create2())) { 205 delete pPxl; 206 } else { 207 hWnd= pPxl->hWnd; 208 } 209 return(Err); 210} 211 212int PxlShader::Create2(void) { 213 int Err= ERR_OK; 214 ATOM hWndClass; 215 WNDCLASS WndClass; 216 RECT R= { 100,100,500,300 }; 217 Zero(WndClass); 218 WndClass.style= CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; 219 WndClass.lpfnWndProc= WndProc; 220 WndClass.hInstance= ghInst; 221 WndClass.lpszClassName= ClassName; 222 DWORD style= WS_OVERLAPPEDWINDOW|WS_VISIBLE; 223 if(!(hWndClass= RegisterClass(&WndClass))) { 224 Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to register the main window class."); 225 } else if(!(hWnd= CreateWindow(ClassName,L"PxlShader",style,R.left,R.top,RWID(R),RHGT(R),0,0,ghInst,(LPVOID)this))) { 226 Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to create the main window."); 227 } 228 return(Err); 229} 230 231/*************************************************************************/ 232/** Window message handler **/ 233/*************************************************************************/ 234INT_PTR CALLBACK PxlShader::WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) { 235 INT_PTR Result= 0; 236 PxlShader *pPxl= 0; 237 if(Msg==WM_CREATE) { 238 CREATESTRUCT *pCreate= (CREATESTRUCT*)lParm; 239 pPxl= Ptr(pCreate->lpCreateParams); 240 } else { 241 pPxl= Ptr(hWnd); 242 } 243 if(!pPxl) { 244 Result= DefWindowProc(hWnd,Msg,wParm,lParm); 245 } else { 246 Result= pPxl->WndProc2(hWnd,Msg,wParm,lParm); 247 } 248 return(Result); 249} 250 251LRESULT PxlShader::WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) { 252 LRESULT Result= 0; 253 switch(Msg) { 254 case WM_CREATE: Result= MsgCreate(hWnd); break; 255 case WM_DESTROY: Result= MsgDestroy(); break; 256 case WM_CLOSE: Result= MsgClose(); break; 257 case WM_TIMER: Result= MsgTimer(); break; 258 case WM_WINDOWPOSCHANGED: Result= MsgMoved(); break; 259 case WM_PAINT: Result= MsgPaint(); break; 260 default: Result= DefWindowProc(hWnd,Msg,wParm,lParm); break; 261 } 262 return(Result); 263} 264 265int PxlShader::MsgCreate(HWND _hWnd) { 266 hWnd= _hWnd; 267 SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)this); 268 SetTimer(hWnd,1,30,0); 269 return(1); 270} 271 272int PxlShader::MsgDestroy(void) { 273 SetWindowLongPtr(hWnd,GWLP_USERDATA,0); 274 delete this; 275 return(1); 276} 277 278int PxlShader::MsgClose(void) { 279 DestroyWindow(hWnd); 280 return(1); 281} 282 283int PxlShader::MsgTimer(void) { 284 ptBall.x+= BallVector.x; 285 if(ptBall.x < rWnd.left || ptBall.x >= rWnd.right) { 286 BallVector.x= -BallVector.x; 287 ptBall.x+= BallVector.x*2; 288 } 289 ptBall.y+= BallVector.y; 290 if(ptBall.y < rWnd.top || ptBall.y >= rWnd.bottom) { 291 BallVector.y= -BallVector.y; 292 ptBall.y+= BallVector.y*2; 293 } 294 if(pEffect) { 295 UINT32 Tint= ((UINT32)rand()<<16)|rand(); 296 pEffect->SetValueByName(L"Tint",Tint); 297 } 298 InvalidateRect(hWnd,0,0); 299 return(1); 300} 301 302int PxlShader::MsgMoved(void) { 303 RECT rNew; 304 GetClientRect(hWnd,&rNew); 305 if(RWID(rNew)!=RWID(rWnd) || RHGT(rNew)!=RHGT(rWnd)) { 306 rWnd= rNew; 307 ReleaseEverything(); 308 } 309 return(1); 310} 311 312int PxlShader::MsgPaint(void) { 313 int Err= ERR_OK; 314 PAINTSTRUCT Pnt; 315 GetClientRect(hWnd,&rWnd); 316 if(BeginPaint(hWnd,&Pnt)) { 317 if(IsErr(Err= DrawCreate())) { 318 Err= Warn(Err,"PxlShader:MsgPaint: DrawCreate() failed."); 319 } else if(IsErr(Err= DrawUpdate())) { 320 Err= Warn(Err,"PxlShader:MsgPaint: DrawUdpate() failed."); 321 } else if(IsErr(Err= DrawShow())) { 322 Err= Warn(Err,"PxlShader:MsgPaint: DrawPaint() failed."); 323 } 324 if(IsErr(Err)) { 325 // Fall back to GDI paint. 326 HBRUSH hbrFill= CreateSolidBrush(RGB(20,30,40)); 327 FillRect(Pnt.hdc,&Pnt.rcPaint,hbrFill); 328 DeleteObject(hbrFill); 329 } 330 EndPaint(hWnd,&Pnt); 331 } 332 ValidateRect(hWnd,0); 333 return(1); 334} 335 336/*************************************************************************/ 337/** DirectX **/ 338/*************************************************************************/ 339int PxlShader::DrawCreate(void) { 340 int Err= ERR_OK; 341 HRESULT WinErr; 342 D2D1_SIZE_U szWnd= { (UINT32)RWID(rWnd), (UINT32)RHGT(rWnd) }; 343 D2D1_DEVICE_CONTEXT_OPTIONS DCOptions= D2D1_DEVICE_CONTEXT_OPTIONS_NONE; 344 if(!pDXGIDevice && IsErr(DrawCreateDX())) { 345 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create DXGI device."); 346 } else if(!pSwapChain && IsErr(Err= DrawCreateSwapChain())) { 347 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create SwapChain."); 348 } else if(!pDXGISurface && !SUCCEEDED(WinErr= pSwapChain->GetBuffer(0,IID_PPV_ARGS(&pDXGISurface)))) { 349 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to retrieve DXGI surface. [%X]",WinErr); 350 } else if(!pD2Factory && IsErr(Err= DrawCreateD2Factory())) { 351 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D factory."); 352 } else if(!pD2Device && !SUCCEEDED(WinErr= pD2Factory->CreateDevice(pDXGIDevice,&pD2Device))) { 353 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D device."); 354 } else if(!pdcDraw && !SUCCEEDED(WinErr= pD2Device->CreateDeviceContext(DCOptions,&pdcDraw))) { 355 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Draw context."); 356 } else if(!pbmImg && IsErr(Err= CreateBitmapBase(pdcDraw,szWnd,pbmImg))) { 357 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create base bitmap."); 358 } else if(!pEffect && IsErr(Err= CreateEffect())) { 359 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create MyEffect."); 360 } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) { 361 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); 362 } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) { 363 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); 364 } 365 return(Err); 366} 367 368int PxlShader::DrawCreateDX(void) { 369 int Err= ERR_OK; 370 HRESULT WinErr; 371 UINT Flags= D3D11_CREATE_DEVICE_BGRA_SUPPORT; 372 static const D3D_FEATURE_LEVEL Levels[]= { 373 D3D_FEATURE_LEVEL_11_1, 374 D3D_FEATURE_LEVEL_11_0, 375 D3D_FEATURE_LEVEL_10_1, 376 D3D_FEATURE_LEVEL_10_0, 377 D3D_FEATURE_LEVEL_9_3, 378 D3D_FEATURE_LEVEL_9_2, 379 D3D_FEATURE_LEVEL_9_1 380 }; 381 D3D_DRIVER_TYPE Type= D3D_DRIVER_TYPE_HARDWARE; 382 UINT ctLevels= ARRAYSIZE(Levels); 383 UINT Version= D3D11_SDK_VERSION; 384 ID3D11Device *pD3D11Device= 0; 385 ID3D11DeviceContext *pD3D11DC= 0; 386 IDXGIAdapter *pDXGIAdapter= 0; 387 if(!SUCCEEDED(WinErr= D3D11CreateDevice(0,Type,0,Flags,Levels,ctLevels,Version,&pD3D11Device,&DxFeatures,&pD3D11DC))) { 388 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: D3D11CreateDevice() failed."); 389 } else if(!SUCCEEDED(WinErr= pD3D11Device->QueryInterface(&pDXGIDevice))) { 390 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI device. [%X]",WinErr); 391 } else if(!SUCCEEDED(WinErr= pDXGIDevice->GetAdapter(&pDXGIAdapter))) { 392 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI adapter. [%X]",WinErr); 393 } else if(!SUCCEEDED(WinErr= pDXGIAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory)))) { 394 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI factory. [%X]",WinErr); 395 } 396 SafeRelease(pDXGIAdapter); 397 SafeRelease(pD3D11Device); 398 SafeRelease(pD3D11DC); 399 return(Err); 400} 401 402int PxlShader::DrawCreateSwapChain(void) { 403 int Err= ERR_OK; 404 HRESULT WinErr; 405 DXGI_SWAP_CHAIN_DESC1 SwapDesc; 406 Zero(SwapDesc); 407 SwapDesc.Format= DXGI_FORMAT_B8G8R8A8_UNORM; 408 SwapDesc.SampleDesc.Count= 1; 409 SwapDesc.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT; 410 SwapDesc.BufferCount= 2; 411 SwapDesc.Scaling= DXGI_SCALING_STRETCH; 412 SwapDesc.SwapEffect= DXGI_SWAP_EFFECT_DISCARD; 413 if(!SUCCEEDED(WinErr= pDXGIFactory->CreateSwapChainForHwnd(pDXGIDevice,hWnd,&SwapDesc,0,0,&pSwapChain))) { 414 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateSwapChain: Unable to create SwapChain. [%X]",WinErr); 415 } 416 return(Err); 417} 418 419int PxlShader::DrawCreateD2Factory(void) { 420 int Err= ERR_OK; 421 HRESULT WinErr; 422 REFIID guid= __uuidof(ID2D1Factory1); 423 D2D1_FACTORY_OPTIONS options; 424 options.debugLevel= D2D1_DEBUG_LEVEL_INFORMATION; 425 // DEBUG_LEVEL will trigger exceptions if EndDraw() fails or the factory is released with 426 // outstanding (unreleased) objects. 427 if(!SUCCEEDED(WinErr= D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,guid,&options,(void**)&pD2Factory))) { 428 Err= Error(ERR_DIRECTX,"PxlShader:DrawCreateD2Factory: Unable to create D2D factory. [%X]",WinErr); 429 } 430 return(Err); 431} 432 433 // Create a targetable bitmap from a DXGI surface. 434 // This serves as the final rendering destination bitmap. 435int PxlShader::CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase) { 436 int Err= ERR_OK; 437 HRESULT WinErr; 438 IDXGISurface *pSurface= 0; 439 D2D1_BITMAP_PROPERTIES1 bmProp; 440 Zero(bmProp); 441 bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET|D2D1_BITMAP_OPTIONS_CANNOT_DRAW; 442 bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_IGNORE); 443 pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY); 444 if(!SUCCEEDED(WinErr= pdcDst->CreateBitmapFromDxgiSurface(pDXGISurface,bmProp,&pbmBase))) { 445 Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapBase: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height); 446 } else { 447 pdcDst->SetTarget(pbmBase); 448 } 449 return(Err); 450} 451 452 // Create a targetable bitmap that can be used for compositing. 453int PxlShader::CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite) { 454 int Err= ERR_OK; 455 HRESULT WinErr; 456 D2D1_BITMAP_PROPERTIES1 bmProp; 457 Zero(bmProp); 458 bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET; 459 bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED); 460 pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY); 461 if(!SUCCEEDED(WinErr= pdcDst->CreateBitmap(szBitmap,0,0,bmProp,&pbmComposite))) { 462 Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapComposite: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height); 463 } else { 464 pdcDst->SetTarget(pbmComposite); 465 } 466 return(Err); 467} 468 469int PxlShader::CreateEffect(void) { 470 int Err= ERR_OK; 471 HRESULT WinErr; 472 if(!SUCCEEDED(WinErr= MyEffect::Register(pD2Factory))) { 473 Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to register MyEffect. [%X]",WinErr); 474 } else if(!SUCCEEDED(WinErr= pdcDraw->CreateEffect(CLSID_MyEffect,&pEffect))) { 475 Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to create MyEffect. [%X]",WinErr); 476 } else { 477 Print(PRINT_INFO,"PxlShader:CreateEffect: OK"); 478 } 479 return(Err); 480} 481 482void PxlShader::ReleaseEverything(void) { 483 SafeRelease(pEffect); 484 SafeRelease(pbmSrc2); 485 SafeRelease(pbmSrc1); 486 SafeRelease(pbmImg); 487 SafeRelease(pdcDraw); 488 SafeRelease(pD2Device); 489 SafeRelease(pD2Factory); 490 SafeRelease(pDXGIDevice); 491 SafeRelease(pDXGISurface); 492 SafeRelease(pSwapChain); 493 SafeRelease(pDXGIFactory); 494} 495 496/*************************************************************************/ 497/** Draw **/ 498/*************************************************************************/ 499int PxlShader::DrawUpdate(void) { 500 int Err= ERR_OK; 501 HRESULT WinErr; 502 pdcDraw->BeginDraw(); 503 pdcDraw->SetTransform(Matrix3x2F::Identity()); 504 pdcDraw->SetTarget(pbmSrc1); 505 pdcDraw->Clear(ColorF(ColorF::Black,0)); 506 D2D1_RECT_F box= { 0,0,80,60 }; 507 pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod))); 508 pdcDraw->SetTarget(pbmSrc2); 509 pdcDraw->Clear(ColorF(ColorF::Black,0)); 510 D2D1_ELLIPSE dot= { {50,50}, 50,50 }; 511 pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen))); 512 pdcDraw->SetTarget(pbmImg); 513 pdcDraw->Clear(ColorF(ColorF::Black,0)); 514 pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y))); 515 pEffect->SetInput(0,pbmSrc1); 516 pEffect->SetInput(1,pbmSrc2); 517 pdcDraw->DrawImage(pEffect); 518 if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) { 519 Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr); 520 ReleaseEverything(); 521 } 522 return(Err); 523} 524 525int PxlShader::DrawShow(void) { 526 int Err= ERR_OK; 527 HRESULT WinErr; 528 DXGI_PRESENT_PARAMETERS PresentParm; 529 Zero(PresentParm); 530 if(!SUCCEEDED(WinErr= pSwapChain->Present1(1,0,&PresentParm))) { 531 Err= Warn(ERR_DIRECTX,"PxlShader:DrawShow: Present() failed. [%X]",WinErr); 532 } 533 return(Err); 534} 535 536/*************************************************************************/ 537/** MyEffect **/ 538/*************************************************************************/ 539MyEffect::MyEffect(void) { 540 Signature= SIGNATURE_MYEFFECT; 541 ctReference= 1; 542 ctInput= 0; 543 Zero(Constants); 544 Constants.tint[2]= 0.50f; 545} 546 547MyEffect::~MyEffect(void) { 548 Signature|= SIGNATURE_INVALID; 549} 550 551ULONG MyEffect::Release(void) { 552 if(--ctReference > 0) 553 return(ctReference); 554 delete this; 555 return(0); 556} 557 558HRESULT MyEffect::QueryInterface(REFIID riid, void **ppInterface) { 559 HRESULT WinErr= S_OK; 560 void *pInterface= 0; 561 if(riid==__uuidof(ID2D1EffectImpl)) { 562 pInterface= reinterpret_cast<ID2D1EffectImpl*>(this); 563 } else if(riid==__uuidof(ID2D1DrawTransform)) { 564 pInterface= static_cast<ID2D1DrawTransform*>(this); 565 } else if(riid==__uuidof(ID2D1Transform)) { 566 pInterface= static_cast<ID2D1Transform*>(this); 567 } else if(riid==__uuidof(ID2D1TransformNode)) { 568 pInterface= static_cast<ID2D1TransformNode*>(this); 569 } else if(riid==__uuidof(ID2D1ComputeTransform)) { 570 Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a compute transform."); 571 WinErr= E_NOINTERFACE; 572 } else if(riid==__uuidof(ID2D1SourceTransform)) { 573 Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a source transform."); 574 WinErr= E_NOINTERFACE; 575 } else if(riid==__uuidof(IUnknown)) { 576 pInterface= this; 577 } else { 578 WinErr= E_NOINTERFACE; 579 } 580 if(ppInterface) { 581 *ppInterface= pInterface; 582 if(pInterface) 583 AddRef(); 584 } 585 return(WinErr); 586} 587 588HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) { 589 HRESULT WinErr= S_OK; 590 static const PCWSTR pszXml = 591 L"<?xml version='1.0'?>\r\n" 592 L"<Effect>\r\n" 593 L" <!-- System Properties -->\r\n" 594 L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n" 595 L" <Property name='Author' type='string' value='nlited systems'/>\r\n" 596 L" <Property name='Category' type='string' value='Experimental'/>\r\n" 597 L" <Property name='Description' type='string' value='My first effect.'/>\r\n" 598 L" <Inputs minimum='0' maximum='2'>\r\n" 599 // Source must be specified. 600 L" <Input name='Source1'/>\r\n" 601 L" <Input name='Source2'/>\r\n" 602 L" </Inputs>\r\n" 603 L" <!-- Custom Properties go here. -->\r\n" 604 L" <Property name='Tint' type='uint32'>\r\n" 605 L" <Property name='DisplayName' type='string' value='Tint'/>\r\n" 606 L" <Property name='Default' type='uint32' value='0'/>\r\n" 607 L" </Property>\r\n" 608 L"</Effect>\r\n" 609 ; 610 static const D2D1_PROPERTY_BINDING Bindings[]= { 611 D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint) 612 }; 613 if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) { 614 Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr); 615 } 616 return(WinErr); 617} 618 619HRESULT __stdcall MyEffect::CreateMyEffect(IUnknown **ppEffect) { 620 HRESULT WinErr= S_OK; 621 *ppEffect= static_cast<ID2D1EffectImpl*>(new MyEffect); 622 if(!*ppEffect) { 623 WinErr= E_OUTOFMEMORY; 624 } 625 return(WinErr); 626} 627 628HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) { 629 HRESULT WinErr= S_OK; 630 ID3DBlob *pCode= 0; 631 ID3DBlob *pError= 0; 632 pCtx= _pCtx; 633 if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"S:\\Src\\HQ\\Dev\\SB\\Chip\\Bugs\\BugsV1\\Out\\Winx64Debug\\FirstShader.cso",&pCode))) { 634 Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr); 635 } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) { 636 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr); 637 } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) { 638 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr); 639 } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) { 640 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr); 641 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) { 642 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr); 643 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) { 644 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr); 645 } else { 646 ctInput= 2; 647 Print(PRINT_INFO,"MyEffect:Initialize: OK."); 648 } 649 SafeRelease(pCode); 650 SafeRelease(pError); 651 return(WinErr); 652} 653 654 // This is a single-transform, single-node graph, SetGraph() should never be called. 655HRESULT MyEffect::SetGraph(ID2D1TransformGraph *pGraph) { 656 Warn(ERR_DIRECTX,"MyEffect:SetGraph: Should not be called."); 657 return(E_NOTIMPL); 658} 659 660HRESULT MyEffect::SetTint(UINT32 Clr) { 661 Constants.tint[0]= (float)((Clr>>16) & 0xFF)/255.0f; 662 Constants.tint[1]= (float)((Clr>> 8) & 0xFF)/255.0f; 663 Constants.tint[2]= (float)((Clr ) & 0xFF)/255.0f; 664 Constants.tint[3]= (float)((Clr>>24) & 0xFF)/255.0f; 665 return(S_OK); 666} 667 668UINT32 MyEffect::GetTint(void) const { 669 UINT32 Clr= 0; 670 Clr|= ((UINT32)(Constants.tint[0]*255.0f) & 0xFF)<<16; 671 Clr|= ((UINT32)(Constants.tint[1]*255.0f) & 0xFF)<< 8; 672 Clr|= ((UINT32)(Constants.tint[2]*255.0f) & 0xFF); 673 Clr|= ((UINT32)(Constants.tint[3]*255.0f) & 0xFF)<<24; 674 return(Clr); 675} 676 677HRESULT MyEffect::PrepareForRender(D2D1_CHANGE_TYPE Type) { 678 HRESULT WinErr= S_OK; 679 pDraw->SetPixelShaderConstantBuffer((BYTE*)&Constants,sizeof(Constants)); 680 return(WinErr); 681} 682 683 // ID2D1DrawTransform 684HRESULT MyEffect::SetDrawInfo(ID2D1DrawInfo *_pDraw) { 685 HRESULT WinErr= S_OK; 686 pDraw= _pDraw; 687 if(!SUCCEEDED(WinErr= pDraw->SetPixelShader(GUID_MyPixelShader))) { 688 Warn(ERR_DIRECTX,"MyEffect:SetDrawInfo: SetPixelShader() failed. [%X]",WinErr); 689 } 690 return(WinErr); 691} 692 693HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const { 694 HRESULT WinErr= S_OK; 695 //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn); 696 if(ctIn==0) { 697 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?"); 698 } else if(ctIn>MAX_INPUT) { 699 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn); 700 WinErr= E_INVALIDARG; 701 } else if(ctIn>0) { 702 prIn[0]= *prOut; 703 for(UINT n1=1;n1<ctIn;n1++) { 704 prIn[n1]= *prOut; 705 } 706 } 707 return(WinErr); 708} 709 710IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) { 711 HRESULT WinErr= S_OK; 712 //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn); 713 if(ctIn==0) { 714 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?"); 715 } else if(ctIn>MAX_INPUT) { 716 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn); 717 WinErr= E_INVALIDARG; 718 } else if(ctIn>0) { 719 *prOut= rIn[0]= prIn[0]; 720 for(UINT n1=1;n1<ctIn;n1++) { 721 rIn[n1]= prIn[n1]; 722 } 723 Zero(*prOutOpaque); 724 } 725 return(WinErr); 726} 727 728IFACEMETHODIMP MyEffect::MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOutInvalid) const { 729 HRESULT WinErr= S_OK; 730 Print(PRINT_DEBUG,"MyEffect:MapInvalidRect:"); 731 // Set entire output to invalid 732 *prOutInvalid= rIn[0]; 733 return(WinErr); 734} 735 736IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const { 737 return(MAX_INPUT); 738} 739 740 //EOF: PXLSHADER.CPP



WebV7 (C)2018 nlited | Rendered by tikope in 58.919ms | 3.22.166.101