1.首先定义一个DX操作类
1 using System; 2 using SlimDX; 3 using SlimDX.Direct3D9; 4 using System.Windows.Interop; 5 using System.Windows.Media; 6 7 public class DX 8 { 9 private enum DirectXStatus 10 { 11 Available, 12 Unavailable_RemoteSession, 13 Unavailable_LowTier, 14 Unavailable_MissingDirectX, 15 Unavailable_Unknown 16 }; 17 18 public static Device Device { get; private set; } 19 public static bool Available { get { return DX.Device != null; } }// = false; 20 21 private static DX _dx; 22 private static DirectXStatus _status = DirectXStatus.Unavailable_Unknown; 23 private static string _statusMessage = ""; 24 25 [System.Runtime.InteropServices.DllImport("user32")] 26 private static extern int GetSystemMetrics(int smIndex); 27 private const int SM_REMOTESESSION = 0x1000; 28 29 // device settings 30 private const Format _adapterFormat = Format.X8R8G8B8; 31 private const Format _backbufferFormat = Format.A8R8G8B8; 32 private const Format _depthStencilFormat = Format.D16; 33 private static CreateFlags _createFlags = CreateFlags.Multithreaded | CreateFlags.FpuPreserve; 34 35 private Direct3D _d3d; 36 37 38 private DX() 39 { 40 initD3D(); 41 if (_d3d != null) 42 initDevice(); 43 //if (!DX.Available) 44 // MessageBox.Show("DirectX硬件加速不可用!\n\n" + _statusMessage, "", MessageBoxButton.OK, MessageBoxImage.Warning); 45 } 46 47 ~DX() 48 { 49 if (DX.Device != null) 50 if (!DX.Device.Disposed) 51 DX.Device.Dispose(); 52 if (_d3d != null) 53 if (!_d3d.Disposed) 54 _d3d.Dispose(); 55 } 56 57 public static void Init() 58 { 59 if (_dx == null) 60 _dx = new DX(); 61 } 62 63 private void initD3D() 64 { 65 if (_d3d != null) 66 return; 67 68 _status = DirectXStatus.Unavailable_Unknown; 69 70 //// assume that we can't run at all under terminal services 71 if (GetSystemMetrics(SM_REMOTESESSION) != 0) 72 { 73 _status = DirectXStatus.Unavailable_RemoteSession; 74 return; 75 } 76 77 int renderingTier = (RenderCapability.Tier >> 16); 78 if (renderingTier < 2) 79 { 80 _status = DirectXStatus.Unavailable_LowTier; 81 _statusMessage = "low tier"; 82 return;//注意:发现某些集成显卡,在这里出去!! 83 } 84 85 try 86 { 87 _d3d = new Direct3DEx(); 88 } 89 catch 90 { 91 try 92 { 93 _d3d = new Direct3D(); 94 } 95 catch (Direct3DX9NotFoundException dfe) 96 { 97 _status = DirectXStatus.Unavailable_MissingDirectX; 98 _statusMessage = "Direct3DX9 Not Found\n" + dfe.Message; 99 return; 100 } 101 catch (Exception e) 102 { 103 _status = DirectXStatus.Unavailable_Unknown; 104 _statusMessage = e.Message; 105 return; 106 } 107 } 108 109 bool ok; 110 Result result; 111 112 ok = _d3d.CheckDeviceType(0, DeviceType.Hardware, _adapterFormat, _backbufferFormat, true, out result); 113 if (!ok) 114 { 115 //Debug.WriteLine("*** failed to CheckDeviceType"); 116 //MessageBox.Show("Failed to CheckDeviceType"); 117 return; 118 } 119 120 ok = _d3d.CheckDepthStencilMatch(0, DeviceType.Hardware, _adapterFormat, _backbufferFormat, _depthStencilFormat, out result); 121 if (!ok) 122 { 123 //Debug.WriteLine("*** failed to CheckDepthStencilMatch"); 124 _statusMessage = "Failed to CheckDepthStencilMatch"; 125 return; 126 } 127 128 Capabilities deviceCaps = _d3d.GetDeviceCaps(0, DeviceType.Hardware); 129 if ((deviceCaps.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0) 130 _createFlags |= CreateFlags.HardwareVertexProcessing; 131 else 132 _createFlags |= CreateFlags.SoftwareVertexProcessing; 133 134 _status = DirectXStatus.Available; 135 } 136 137 private void initDevice() 138 { 139 if (_status != DirectXStatus.Available) 140 return; 141 142 HwndSource hwnd = new HwndSource(0, 0, 0, 0, 0, 0, 0, "SlimDX_Wnd", IntPtr.Zero); 143 PresentParameters pp = new PresentParameters(); 144 //pp.SwapEffect = SwapEffect.Copy; 145 //pp.DeviceWindowHandle = hwnd.Handle; 146 pp.Windowed = true; 147 pp.PresentFlags = PresentFlags.Video; 148 pp.SwapEffect = SwapEffect.Discard; 149 //pp.BackBufferCount = 1; 150 //pp.BackBufferWidth = 320; 151 //pp.BackBufferHeight = 240; 152 //pp.BackBufferFormat = _backbufferFormat; 153 //pp.AutoDepthStencilFormat = _depthStencilFormat; 154 try 155 { 156 DeviceType deviceType = DeviceType.Hardware; 157 if (_d3d is Direct3DEx) 158 DX.Device = new DeviceEx((Direct3DEx)_d3d, 0, deviceType, hwnd.Handle, _createFlags, pp); 159 else 160 DX.Device = new Device(_d3d, 0, deviceType, hwnd.Handle, _createFlags, pp); 161 } 162 catch (Exception ex) 163 { 164 //Debug.WriteLine("Exception in Direct3DReset " + ex.StackTrace); 165 //Debug.WriteLine("Exception in Direct3DReset " + ex.Message); 166 } 167 } 168 }
2.定义准备显卡硬件,和释放显卡硬件方法
定义一些变量
/// <summary> /// 离屏表面 /// </summary> private Surface _offscrn; /// <summary> /// 交换链 /// </summary> private SwapChain _swapChain; private D3DImage _d3dImage = null;
1 /// <summary> 2 /// 准备DirectX显卡硬件 3 /// </summary> 4 private bool prepareHardware(VideoFormat videoFormat, int videoWidth, int videoHeight)//, VideoFormat videoFormat) 5 { 6 if (!DX.Available) 7 return true; 8 9 try 10 { 11 SlimDX.Direct3D9.Format format = SlimDX.Direct3D9.Format.A8R8G8B8; 12 if (videoFormat == VideoFormat.Yuv420) 13 format = (SlimDX.Direct3D9.Format)0x32315659; 14 if (_offscrn != null) 15 if (videoWidth == _offscrn.Description.Width && videoHeight == _offscrn.Description.Height && _offscrn.Description.Format == format) 16 return true; 17 18 releaseHardware(); 19 _offscrn = Surface.CreateOffscreenPlain(DX.Device, videoWidth, videoHeight, format, Pool.Default); 20 PresentParameters pp = new PresentParameters(); 21 pp.Windowed = true; 22 pp.PresentFlags = PresentFlags.Video; 23 pp.SwapEffect = SwapEffect.Discard; 24 pp.BackBufferCount = 1; 25 pp.BackBufferWidth = videoWidth; 26 pp.BackBufferHeight = videoHeight; 27 _swapChain = new SwapChain(DX.Device, pp); 28 return true; 29 } 30 catch 31 { 32 return false; 33 } 34 } 35 /// <summary> 36 /// 释放DirectX显卡硬件 37 /// </summary> 38 private void releaseHardware() 39 { 40 if (!DX.Available) 41 return; 42 if (_offscrn != null) 43 if (!_offscrn.Disposed) 44 _offscrn.Dispose(); 45 _offscrn = null; 46 if (_swapChain != null) 47 if (!_swapChain.Disposed) 48 _swapChain.Dispose(); 49 _swapChain = null; 50 }
3.
private void drawFrame(VideoFormat videoFormat, int width, int height, IntPtr Y, IntPtr U, IntPtr V) { if (!prepareHardware(videoFormat, width, height)) return; if (_swapChain == null) return; DataRectangle dr = _offscrn.LockRectangle(LockFlags.None);//在离屏表面上锁定一个矩形 drawYuv420(width, height, Y, U, V, dr.Data.DataPointer, dr.Pitch);//DataPointer 内部指针指向当前流的存储备份; Pitch 两个连续的行之间的数据的字节数 _offscrn.UnlockRectangle();//解锁矩形 using (Surface bb = _swapChain.GetBackBuffer(0))//从交换链中检索一个后台缓冲区 { System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bb.Description.Width, bb.Description.Height); _swapChain.Device.StretchRectangle(_offscrn, rect, bb, rect, TextureFilter.None);//将后台缓冲区的内容交换到前台缓冲区 _swapChain.Device.Present();//呈现后台缓冲区序列中下一个后台缓冲区的内容 _d3dImage.Lock(); _d3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, bb.ComPointer); _d3dImage.AddDirtyRect(new Int32Rect(0, 0, _d3dImage.PixelWidth, _d3dImage.PixelHeight)); _d3dImage.Unlock(); } } private void drawYuv420(int width, int height, IntPtr Y, IntPtr U, IntPtr V, IntPtr dest, int pitch) { IntPtr py = dest; IntPtr pv = py + (pitch * height); IntPtr pu = pv + ((pitch * height) / 4); int w2 = width / 2, pitch2 = pitch / 2; for (int y = 0; y < height; y++) { CopyMemory(py, Y + y * width, (uint)width); py += pitch; if ((y & 1) != 0) continue; int offset = y / 2 * w2; CopyMemory(pu, U + offset, (uint)w2); CopyMemory(pv, V + offset, (uint)w2); pu += pitch2; pv += pitch2; } } [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")] private static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);