[DirectX] .Net WinForm์์ GDI+์ SharpDX ์ฌ์ฉํ๊ธฐ (์์ ํฌํจ)
SharpDX vs GDI+
์ง๋ ํฌ์คํ ์์ DirectX์ GDI+์ ๊ธฐ๋ณธ์ ์ธ ์ฐจ์ด์ ๊ณผ SharpDX๊ฐ ๋ฌด์์ธ์ง ์์๋ณด์์ต๋๋ค.
[.Net] DirectX์ GDI+์ ์ฐจ์ด์ , ๊ทธ๋ฆฌ๊ณ SharpDX ์ดํดํ๊ธฐ
๊ฐ๋จํ๊ฒ ์์ฝํ์๋ฉด, 2D ์ด๋ฏธ์ง ๋ ๋๋ง ๊ธฐ์ค์ผ๋ก ํ๋์จ์ด ๊ฐ์์ ์ง์ํ๋์ ์ฐจ์ด์ ์ด ์๋ค๊ณ ๋ณด๋ฉด ๋๊ฒ ์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ WinForm ํ๋ก์ ํธ์์ SharpDX๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง, ๊ทธ๋ฆฌ๊ณ GDI+ ๋๋นํ์ฌ ์ด๋ค ์ฐจ์ด๊ฐ ์๋์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ฐ๋ผ ํ๊ธฐ
์์ ์ฝ๋๋ Visual Studio 2022 ํ๊ฒฝ์ผ๋ก ์ ์ํ์ต๋๋ค. WinForm์ Picture Box๋ฅผ ์ถ๊ฐํ๊ณ , ์ ํํ ๋ฐฉ์(GDI+ ๋๋ DirectX)์ ๋ฐ๋ผ Picture Box์ ์ด๋ฏธ์ง๋ฅผ ์ด๋ป๊ฒ ๋ ๋๋ง ํ๋์ง ๋ณด์ฌ์ค๋๋ค.
WinForm ํ๋ก์ ํธ ์์ฑํ๊ธฐ
ExamDirectX
์ด๋ฆ์ผ๋ก Windows Forms ์ฑ(.NET Framework)๋ฅผ ์์ฑํฉ๋๋ค.
UI Control ๋ฐฐ์นํ๊ธฐ
์๋ ๊ทธ๋ฆผ์ฒ๋ผ, UI๋ Picture Box์ ๋ฒํผ, ๋ผ๋์ค ๋ฒํผ์ผ๋ก ๊ตฌ์ฑํ์ต๋๋ค.
SharpDX NuGet ํจํค์ง ์ค์นํ๊ธฐ
NuGet ํจํค์ง ๊ด๋ฆฌ์์ SharpDX
๋ฅผ ๊ฒ์ํ๊ณ ์๋์ ํจํค์ง๋ค์ ์ค์นํฉ๋๋ค.
SharpDX ๊ตฌํํ๊ธฐ
๋ณธ๋ฌธ ํ๋จ์ ์ฒจ๋ถ๋ ์์ ์ฝ๋์๋ MyDirectX.cs
ํ์ผ์ด ์์ต๋๋ค. ์ด ํ์ผ์ SharpDX ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์ด๊ธฐํํ๊ณ , ํ์ผ์ ๋ถ๋ฌ์ค๊ณ , ๋์ ์ปจํธ๋กค์ ๋ ๋๋ง ํ๋์ง ์ฝ๋๊ฐ ๊ตฌํ๋์ด ์์ต๋๋ค. ์ฝ๋์๋ ์ฃผ์์ผ๋ก ์ค๋ช
์ ๋จ๊ฒจ ๋์์ง๋ง ๋ณธ๋ฌธ์์๋ ์ค๋ช
ํ๊ฒ ์ต๋๋ค.
๊ฐ ๊ฐ์ฒด ๋ณ ์ฉ๋
Picture Box๋ GDI+ ๊ธฐ๋ฐ์ ์ปจํธ๋กค์ ๋๋ค. DirectX ๊ฐ์ฒด๋ก ํด๋น ์ปจํธ๋กค์ ๋ ๋๋ง ํ๊ธฐ ์ํด ์๋์ ๊ธฐ๋ณธ ๊ฐ์ฒด๋ค์ด ์ฌ์ฉ๋ฉ๋๋ค.
//DirectX 2D ๊ทธ๋ํฝ ๋ ๋๋ง์ ํ์ํ ๋ฆฌ์์ค๋ฅผ ์ ๊ณต
SharpDX.Direct2D1.Factory2 _factory2D = null;
//GPU ํ๋์จ์ด์ ์ ๊ทผํ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณต
SharpDX.Direct3D11.Device _device = null;
//๋ฐฑ ๋ฒํผ์ ํ๋ก ํธ ๋ฒํผ๋ฅผ ์ค์(ex: ๋๋ธ ๋ฒํผ๋ง)ํด์ฃผ๋ ๊ธฐ๋ฅ
SharpDX.DXGI.SwapChain _swapChain = null;
//๋ ๋๋ง์ด ์ํ๋๋ ํ๊ฒ
SharpDX.Direct2D1.RenderTarget _renderTarget2D = null;
//DirectX 2D ๋นํธ๋งต
SharpDX.Direct2D1.Bitmap _bitmap = null;
PictureBox ์ปจํธ๋กค๊ณผ ์ฐ๋ํ์ฌ ์ด๊ธฐํํ๊ธฐ
์ผ๋ฐ์ ์ผ๋ก ํ๋ฉด์ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋๋ฝ๊ฒ ๋ ๋๋ง ํ๊ธฐ ์ํด ๋๋ธ ๋ฒํผ๋ง
์ ์ฌ์ฉํฉ๋๋ค. ํ๋ฉด์ ๋ณด์ด๋ ๋ฒํผ(ํ๋ฐํธ ๋ฒํผ)์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ฒ๋ฆฌํ๋ ๋ฒํผ(๋ฐฑ ๋ฒํผ) ๋ ๊ฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ์ค์ ์ฒด์ธ(Swap Chain)
์ ์ด ๋ฐฑ ๋ฒํผ์ ํ๋ก ํธ ๋ฒํผ๋ฅผ ์ค์ ํ์ฌ ์ฌ์ฉ์์๊ฒ ๋ถ๋๋ฌ์ด ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋๋ก ํฉ๋๋ค.
์๋์ ์ฝ๋๋ฅผ ์ํํ๋ฉด _renderTarget2D๋ PictureBox์ ์ฐ๋๋ฉ๋๋ค.
public void InitializeControl(PictureBox control)
{
//์ค์ ์ฒด์ธ์ ๋ํ ์ค์
var desc = new SwapChainDescription()
{
BufferCount = 1, //์ค์ ์ฒด์ธ์ ์ฌ์ฉ๋ ๋ฒํผ์ ์
ModeDescription = new ModeDescription(control.Width, control.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm),
//Rational: ํ๋ฉด ๊ฐฑ์ ์๋ 1/60
IsWindowed = true, //์ค์ ์ฒด์ธ์ด ์ฐฝ ๋ชจ๋์์ ๋์ํ๋๋ก ์ค์
OutputHandle = control.Handle, //์ถ๋ ฅ์ด ์ด๋ฃจ์ด์ง ์ฐฝ์ ํธ๋ค
SampleDescription = new SampleDescription(1, 0), //๋ฉํฐ์ํ๋ง์ ์์ค
SwapEffect = SwapEffect.Discard, //์ค์ ์ฒด์ธ์ ์ค์ ํจ๊ณผ. Discard: ์ค์ ์ดํ ๋ฐฑ ๋ฒํผ ์ญ์
Usage = Usage.RenderTargetOutput //GPU๊ฐ ์ด ์์์ ๊ทธ๋ํฝ ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ธ ์ ์์์ ์๋ฏธ
};
_targetWindowSize.Left = 0;
_targetWindowSize.Top = 0;
_targetWindowSize.Right = control.Width;
_targetWindowSize.Bottom = control.Height;
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, desc, out _device, out _swapChain);
//DirectX 2D ๊ทธ๋ํฝ ๋ ๋๋ง์ ํ์ํ ๋ฆฌ์์ค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ๊ธฐ๋ฅ์ ์ ๊ณต
_factory2D = new SharpDX.Direct2D1.Factory2();
//Surface๋ ๊ทธ๋ํฝ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๊ทธ๋ฆฌ๊ธฐ ์์
์ ์ํํ๋ ๋ฐ ์ฌ์ฉ๋๋ ํด๋์ค
var backBuffer = Surface.FromSwapChain(_swapChain, 0);
var properties = new RenderTargetProperties(new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied));
_renderTarget2D = new RenderTarget(_factory2D, backBuffer, properties);
}
ํ์ผ๋ก๋ถํฐ SharpDX ๋นํธ๋งต ์์ฑํ๊ธฐ
WIC(windows Imaging Component)
๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง ํ์ผ์ ๋ถ๋ฌ์จ ํ ๋ ๋๋ง ํ๊น์ ์ฌ์ฉํ ์ ์๋ Direct2D ๋นํธ๋งต์ผ๋ก ์์ฑํฉ๋๋ค.
public void LoadBitmap(string filename)
{
//Bitmap ๋์ฝ๋/์ธ์ฝ๋, ํฌ๋งท ๋ณ๊ฒฝ, ์ค์ผ์ผ๋ฌ ๋ฑ ์ง์
var wicFactory = new SharpDX.WIC.ImagingFactory2();
//ํ์ผ๋ก๋ถํฐ ์ด๋ฏธ์ง ๋ถ๋ฌ์ค๊ธฐ
var wicDecoder = new SharpDX.WIC.BitmapDecoder(wicFactory, filename, SharpDX.WIC.DecodeOptions.CacheOnDemand);
//ํ์ผ๋ก๋ถํฐ ๋ถ๋ฌ์จ ๋์ฝ๋์ ์ฒซ ํ๋ ์ ๊ฐ์ ธ์ค๊ธฐ
//์ด๋ฏธ์ง ํ์ผ์ ํ๋์ ํ๋ ์์ด์ง๋ง, GIF์ ๊ฒฝ์ฐ ์ฌ๋ฌ ํ๋ ์
var wicFrame = wicDecoder.GetFrame(0);
//ํฌ๋งท ์ปจ๋ฒํฐ ์์ฑ ๋ฐ ์ด๊ธฐํ
var converter = new SharpDX.WIC.FormatConverter(wicFactory);
converter.Initialize(wicFrame, SharpDX.WIC.PixelFormat.Format32bppPRGBA);
//๋ณํ๋ ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ Direct2D ๋นํธ๋งต์ผ๋ก ๋ณํ
_bitmap = SharpDX.Direct2D1.Bitmap.FromWicBitmap(_renderTarget2D, converter);
//๊ฐ์ฒด ์๋ฉธ
converter.Dispose();
wicFrame.Dispose();
wicDecoder.Dispose();
wicFactory.Dispose();
}
ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ
ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ํด ์๋์ ์ฝ๋๊ฐ ์ํ๋ฉ๋๋ค. ํนํ ๋ง์ง๋ง ๋ผ์ธ์ ์ฝ๋๊ฐ ์ค์ํ๋ฐ์. Present
ํจ์๋ฅผ ํธ์ถํด์ผ ํ๋ฉด์ ๋ณด์
๋๋ค. ์ฒซ ๋ฒ์งธ ์ธ์๋ ๋ชจ๋ํฐ์ ๋ฆฌํ๋ ์ ์๋(VSync)์ ๋๊ธฐํํ๋ ์ธ์์
๋๋ค. 0์ ์ฆ์ ํ๋ฉด์ ํ์ํ๊ณ , 1์ ๋ชจ๋ํฐ์ ๊ฐฑ์ ์๋์ ๋๊ธฐ๋ฅผ ๋ง์ถฅ๋๋ค. ๋ ๋ฒ์งธ ์ธ์๋ VSync์ ๊ด๋ จํ์ฌ ๋์์ ์ค์ ํ๋ ํ๋๊ทธ์
๋๋ค. ํน์ ํจ๊ณผ๋ฅผ ์ป๊ณ ์ถ๋ค๋ฉด ํ๋๊ทธ๋ฅผ ์ค์ ํ๋ฉด ๋์ง๋ง ์ฑ๋ฅ ์ ํ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ ์ ์๊ณ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
public void Render()
{
//๋ ๋๋ง ์์
์์
_renderTarget2D.BeginDraw();
//๋ ๋๋ง ํ๋ฉด ๋น์ฐ๊ธฐ(ํน์ ์์ ์ฑ์ฐ๊ธฐ ๊ฐ๋ฅ)
_renderTarget2D.Clear(new SharpDX.Mathematics.Interop.RawColor4(1.0f, 1.0f, 1.0f, 1.0f));
//1:1 ๋น์จ๋ก ๊ทธ๋ฆฌ๊ธฐ
//_renderTarget2D.DrawBitmap(_bitmap, 1.0f, SharpDX.Direct2D1.BitmapInterpolationMode.Linear);
//๋ ๋๋ง ํ๊ฒ์ ์ฑ์์ ๊ทธ๋ฆฌ๊ธฐ
_renderTarget2D.DrawBitmap(_bitmap, _targetWindowSize, 1.0f, SharpDX.Direct2D1.BitmapInterpolationMode.Linear);
//๋ ๋๋ง ์์
์ข
๋ฃ
_renderTarget2D.EndDraw();
//์ค์ ์ฒด์ธ์ ๋ ๋๋ง ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ํ์ํ๋ ์ญํ
_swapChain.Present(1, PresentFlags.None);
}
๊ฐ์ฒด ์๋ฉธ
๋ ์ด์ ์ฌ์ฉํ์ง ์๋ ๊ฐ์ฒด๋ ์๋ฉธํฉ๋๋ค.
public void Dispose()
{
_renderTarget2D?.Dispose();
_renderTarget2D = null;
_swapChain?.Dispose();
_swapChain = null;
_device?.Dispose();
_device = null;
_factory2D?.Dispose();
_factory2D = null;
_bitmap?.Dispose();
_bitmap = null;
}
๋ฒํผ ๋์
๋ผ๋์ค ๋ฒํผ์ผ๋ก GDI+ ๋๋ DirectX๋ฅผ ์ ํํ ํ ์คํ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๊ฐ ๋ฐฉ์ ๋ณ ๋ ๋๋ง์ ์ํ ์ค๋ ๋ ํจ์๊ฐ ๋์ํฉ๋๋ค. CPU ๋ฐ GPU ์ฌ์ฉ์จ์ ํ์ธํ๊ธฐ ์ํด 500ํ ๋ฐ๋ณตํ๋๋ก ๊ตฌํํ์ต๋๋ค.
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog dlg = new OpenFileDialog();
if(dlg.ShowDialog() == DialogResult.OK)
{
Thread thread = null;
if (rbtnDirectX.Checked == true)
{
_directX.LoadBitmap(dlg.FileName);
thread = new Thread(threadFuncDirectX);
}
else
{
_bitmap = new Bitmap(dlg.FileName);
//...
thread = new Thread(threadFuncGDI);
}
thread.Start();
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
private void threadFuncDirectX()
{
for (int i = 0; i < 500; i++)
{
Thread.Sleep(30);
_directX.Render();
}
}
private void threadFuncGDI()
{
for (int i = 0; i < 500; i++)
{
Thread.Sleep(30);
_graphics.DrawImage(_bitmap, new Rectangle(0, 0, pbView.Width, pbView.Height));
}
}
๋์ ๊ฒฐ๊ณผ
์ธํฐ๋ท์์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๋ค์ด๋ฐ์ต๋๋ค. ์ ๋ 24MB์ ๊ณ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
GDI+๋ก ๋์ํ๋ฉด CPU ๋ถํ๊ฐ ์ฝ 10%๊น์ง ์ฆ๊ฐํฉ๋๋ค. GPU๋ ์ฌ์ฉํ์ง ์์ผ๋ฏ๋ก ๋ฐ๋ก ์ฌ์ฉ๋์ด ์์ต๋๋ค.
๋ฐ๋ฉด, DirectX๋ก ๋์ํ๋ฉด CPU ๋ถํ๊ฐ ๊ฑฐ์ ์์ผ๋ฉฐ GPU ์ฌ์ฉ๋์ด ์ฆ๊ฐํฉ๋๋ค.
์ ์ฒด ์ฝ๋๋ ์๋ ์ฒจ๋ถ๋ ์์ ํ์ผ์ ์ฐธ๊ณ ํ์ธ์.
'Programming > DirectX' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[DirectX] DirectX์ GDI+์ ์ฐจ์ด์ , ๊ทธ๋ฆฌ๊ณ SharpDX ์ดํดํ๊ธฐ (0) | 2023.06.06 |
---|
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[DirectX] DirectX์ GDI+์ ์ฐจ์ด์ , ๊ทธ๋ฆฌ๊ณ SharpDX ์ดํดํ๊ธฐ
[DirectX] DirectX์ GDI+์ ์ฐจ์ด์ , ๊ทธ๋ฆฌ๊ณ SharpDX ์ดํดํ๊ธฐ
2023.06.06