[PR]
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
プログラミング、3DCGとその他いろいろについて
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
using System.Windows.Forms;class Program{static void Main(){using (Form form = new Form()){Application.Run(form);}}}
実行結果は一見上の例と同じです。class Program{static void Main(){using (Game game = new Game()){game.Run();}}}class Game : System.Windows.Forms.Form{protected override void OnPaint(System.Windows.Forms.PaintEventArgs e){base.OnPaint(e);Draw();Invalidate();}protected virtual void Draw(){//draw 3DCG}public void Run(){System.Windows.Forms.Application.Run(this);}}
この方法の良いところは、Paintイベントがなんども実行されるなんてことが無くなっているというところです。class Program{static void Main(){using (Game game = new Game()){game.Run();}}}class Game : System.Windows.Forms.Form{public void Run(){this.Show();while (Created){Draw();System.Windows.Forms.Application.DoEvents();}}protected virtual void Draw(){//draw 3DCG}}
この方法は他の方法と比べてややこしいですが、class Program{static void Main(){using (Game game = new Game()){game.Run();}}}struct Message{public System.IntPtr hWnd;public uint msg;public System.IntPtr wParam;public System.IntPtr lParam;public uint time;public System.Drawing.Point pt;}class Win32Api{[System.Security.SuppressUnmanagedCodeSecurity] //for performance[System.Runtime.InteropServices.DllImport("user32.dll")]public static extern bool PeekMessage(out Message msg,System.IntPtr hWnd,uint messageFilterMin,uint messageFilterMax,uint flags);}class Game : System.Windows.Forms.Form{bool AppStillIdle{get{Message msg;return !Win32Api.PeekMessage(out msg, System.IntPtr.Zero, 0, 0, 0);}}public void Run(){System.Windows.Forms.Application.Idle += delegate{while (AppStillIdle){Draw();}};System.Windows.Forms.Application.Run(this);}protected virtual void Draw(){//draw 3DCG}}
public sealed class MessagePump
public static void Run(Form form, MainLoop mainLoop);
public delegate void MainLoop();
class Program{static void Main(){using (Game game = new Game()){game.Run();}}}class Game : System.Windows.Forms.Form{public void Run(){SlimDX.Windows.MessagePump.Run(this, Draw);}protected virtual void Draw(){//draw 3DCG}}
void GroupMemoryBarrierWithGroupSync();
groupshared int data[100];
using System.Collections.Generic; using System.Linq; using SlimDX; using SlimDX.Direct3D11; using SlimDX.D3DCompiler; class Program { static Buffer bufferSum; static void Main(string[] args) { Device device = new Device(DriverType.Hardware); bufferSum = createStructuredBuffer( device, 128 * sizeof(int), BindFlags.UnorderedAccess ); initComputeShader(device); device.ImmediateContext.Dispatch(1, 1, 1); writeBuffer(device, bufferSum); } static void initComputeShader(Device device) { device.ImmediateContext.ComputeShader.SetUnorderedAccessView( new UnorderedAccessView(device, bufferSum), 0 ); ShaderBytecode shaderBytecode = ShaderBytecode.CompileFromFile( "MyShader.fx", "MyComputeShader", "cs_5_0", ShaderFlags.None, EffectFlags.None ); device.ImmediateContext.ComputeShader.Set( new ComputeShader(device, shaderBytecode) ); } static void writeBuffer(Device device, Buffer buffer) { Buffer cpuAccessibleBuffer = createCpuAccessibleBuffer(device, buffer.Description.SizeInBytes); device.ImmediateContext.CopyResource(buffer, cpuAccessibleBuffer); int[] readBack = readBackFromGpu(cpuAccessibleBuffer); foreach (var number in readBack) { System.Console.WriteLine(number); } } static Buffer createStructuredBuffer(Device device, int sizeInBytes, BindFlags bindFlags) { return new Buffer( device, new BufferDescription { SizeInBytes = sizeInBytes, BindFlags = bindFlags, OptionFlags = ResourceOptionFlags.StructuredBuffer, StructureByteStride = sizeof(int) } ); } static Buffer createCpuAccessibleBuffer(Device device, int sizeInBytes) { return new Buffer( device, new BufferDescription { SizeInBytes = sizeInBytes, CpuAccessFlags = CpuAccessFlags.Read, Usage = ResourceUsage.Staging } ); } static int[] readBackFromGpu(Buffer from) { DataBox dataBox = from.Device.ImmediateContext.MapSubresource( from, MapMode.Read, MapFlags.None ); int elementCount = (int)(dataBox.Data.Length / sizeof(int)); return dataBox.Data.ReadRange<int>(elementCount); } }
RWStructuredBuffer<int> MyBuffer : register(u0);
static const int ElementCount = 128;groupshared int data[ElementCount];
int getSum(){int result = 0;
for(int i = 0; i < ElementCount; i++){result += data[i];}
return result;}
[numthreads(ElementCount, 1, 1)]void MyComputeShader(uint groupIndex : SV_GroupIndex ){int time = 0;
//スレッドによって処理時間が変わるfor(int i = 0; i < groupIndex; i++){time++;}
data[groupIndex] = time;//GroupMemoryBarrierWithGroupSync();MyBuffer[groupIndex] = getSum();}
1951777886 1951777886 1951777886 1951777886 1951777886 1951777886 1951777886 1951777886 1951777886 ..(中略) 1951777886 8128 8128 8128 8128 8128 8128 8128 8128 ..(中略) 8128
public class ShaderResourceView : ResourceView
public ShaderResourceView(Device device, Resource resource);
public void SetShaderResources( ShaderResourceView[] resourceViews, int startSlot, int count );
T Operator[](in uint indexPosition);
using System.Collections.Generic; using System.Linq; using SlimDX; using SlimDX.Direct3D11; using SlimDX.D3DCompiler; class Program { static Buffer bufferSum; static Buffer buffer0; static Buffer buffer1; const int ElementCount = 20; static void Main(string[] args) { Device device = new Device(DriverType.Hardware); bufferSum = createStructuredBuffer( device, Enumerable.Range(0, ElementCount).ToArray(), BindFlags.UnorderedAccess ); buffer0 = createStructuredBuffer( device, Enumerable.Range(0, ElementCount).ToArray(), BindFlags.ShaderResource ); buffer1 = createStructuredBuffer( device, Enumerable.Range(0, ElementCount).ToArray(), BindFlags.ShaderResource ); initComputeShader(device); device.ImmediateContext.Dispatch(ElementCount, 1, 1); writeBuffer(device, bufferSum); } static void initComputeShader(Device device) { device.ImmediateContext.ComputeShader.SetUnorderedAccessView( new UnorderedAccessView(device, bufferSum), 0 ); device.ImmediateContext.ComputeShader.SetShaderResources( new[] { new ShaderResourceView(device, buffer0), new ShaderResourceView(device, buffer1), }, 0, 2 ); ShaderBytecode shaderBytecode = ShaderBytecode.CompileFromFile( "MyShader.fx", "MyComputeShader", "cs_4_0", ShaderFlags.None, EffectFlags.None ); device.ImmediateContext.ComputeShader.Set( new ComputeShader(device, shaderBytecode) ); } static void writeBuffer(Device device, Buffer buffer) { Buffer cpuAccessibleBuffer = createCpuAccessibleBuffer(device, buffer.Description.SizeInBytes); device.ImmediateContext.CopyResource(buffer, cpuAccessibleBuffer); int[] readBack = readBackFromGpu(cpuAccessibleBuffer); foreach (var number in readBack) { System.Console.WriteLine(number); } } static Buffer createStructuredBuffer(Device device, int[] initialData, BindFlags bindFlags) { DataStream initialDataStream = new DataStream(initialData, true, true); return new Buffer( device, initialDataStream, new BufferDescription { SizeInBytes = (int)initialDataStream.Length, BindFlags = bindFlags, OptionFlags = ResourceOptionFlags.StructuredBuffer, StructureByteStride = sizeof(int) } ); } static Buffer createCpuAccessibleBuffer(Device device, int sizeInBytes) { return new Buffer( device, new BufferDescription { SizeInBytes = sizeInBytes, CpuAccessFlags = CpuAccessFlags.Read, Usage = ResourceUsage.Staging } ); } static int[] readBackFromGpu(Buffer from) { DataBox data = from.Device.ImmediateContext.MapSubresource( from, MapMode.Read, MapFlags.None ); return getArrayInt32(data.Data); } static int[] getArrayInt32(DataStream stream) { int[] buffer = new int[stream.Length / sizeof(int)]; stream.ReadRange(buffer, 0, buffer.Length); return buffer; } }
RWStructuredBuffer<int> BufferSum : register(u0);StructuredBuffer<int> Buffer0 : register(t0);StructuredBuffer<int> Buffer1 : register(t1);
[numthreads(1, 1, 1)]void MyComputeShader(uint3 threadID : SV_DispatchThreadID ){BufferSum[threadID.x] = Buffer0[threadID.x] + Buffer1[threadID.x];}
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
public void SetUnorderedAccessViews( UnorderedAccessView[] unorderedAccessViews, int startSlot, int count );
とあるとき、 RWStructuredBuffer<int> BufferSum;RWStructuredBuffer<int> Buffer0;RWStructuredBuffer<int> Buffer1;
: register( [shader_profile], Type#[subcomponent])shader_profileはつけるつけないは自由のオプションですが、"ps_5_0"等のシェーダープロファイルです。
Type | 対応するリソース |
b | 定数バッファ |
t | テクスチャとテクスチャバッファ |
c | Buffer offset |
s | Sampler |
u | Unordered Access View |
RWStructuredBuffer<int> BufferSum : register(u0);RWStructuredBuffer<int> Buffer0 : register(u1);RWStructuredBuffer<int> Buffer1 : register(u2);
RWStructuredBuffer<int> Buffer0 : register(u1);RWStructuredBuffer<int> Buffer1 : register(u2);
RWStructuredBuffer<int> BufferSum : register(u0);
using System.Collections.Generic; using System.Linq; using SlimDX; using SlimDX.Direct3D11; using SlimDX.D3DCompiler; class Program { static Buffer bufferSum; static Buffer buffer0; static Buffer buffer1; static void Main(string[] args) { Device device = new Device(DriverType.Hardware); bufferSum = createStructuredBuffer(device, Enumerable.Range(0, 10).ToArray()); buffer0 = createStructuredBuffer(device, Enumerable.Range(0, 10).ToArray()); buffer1 = createStructuredBuffer(device, Enumerable.Range(0, 10).ToArray()); initComputeShader(device); device.ImmediateContext.Dispatch(10, 1, 1); writeBuffer(device, bufferSum); } static void initComputeShader(Device device) { device.ImmediateContext.ComputeShader.SetUnorderedAccessViews( new[] { new UnorderedAccessView(device, bufferSum), new UnorderedAccessView(device, buffer0), new UnorderedAccessView(device, buffer1), }, 0, 3 ); ShaderBytecode shaderBytecode = ShaderBytecode.CompileFromFile( "MyShader.fx", "MyComputeShader", "cs_5_0", ShaderFlags.None, EffectFlags.None ); device.ImmediateContext.ComputeShader.Set( new ComputeShader(device, shaderBytecode) ); } static void writeBuffer(Device device, Buffer buffer) { Buffer cpuAccessibleBuffer = createCpuAccessibleBuffer(device, buffer.Description.SizeInBytes); device.ImmediateContext.CopyResource(buffer, cpuAccessibleBuffer); int[] readBack = readBackFromGpu(cpuAccessibleBuffer); foreach (var number in readBack) { System.Console.WriteLine(number); } } static Buffer createStructuredBuffer(Device device, int[] initialData) { DataStream initialDataStream = new DataStream(initialData, true, true); return new Buffer( device, initialDataStream, new BufferDescription { SizeInBytes = (int)initialDataStream.Length, BindFlags = BindFlags.UnorderedAccess, OptionFlags = ResourceOptionFlags.StructuredBuffer, StructureByteStride = sizeof(int) } ); } static Buffer createCpuAccessibleBuffer(Device device, int sizeInBytes) { return new Buffer( device, new BufferDescription { SizeInBytes = sizeInBytes, CpuAccessFlags = CpuAccessFlags.Read, Usage = ResourceUsage.Staging } ); } static int[] readBackFromGpu(Buffer from) { DataBox data = from.Device.ImmediateContext.MapSubresource( from, MapMode.Read, MapFlags.None ); return getArrayInt32(data.Data); } static int[] getArrayInt32(DataStream stream) { int[] buffer = new int[stream.Length / sizeof(int)]; stream.ReadRange(buffer, 0, buffer.Length); return buffer; } }
RWStructuredBuffer<int> BufferSum : register(u0);RWStructuredBuffer<int> Buffer0 : register(u1);RWStructuredBuffer<int> Buffer1 : register(u2);
[numthreads(1, 1, 1)]void MyComputeShader(uint3 threadID : SV_DispatchThreadID ){BufferSum[threadID.x] = Buffer0[threadID.x] + Buffer1[threadID.x];}
0 2 4 6 8 10 12 14 16 18今回やっていることはこうです:
public ComputeShaderWrapper ComputeShader { get; }SlimDX.Direct3D11.ComputeShaderWrapperクラスは
public void SetUnorderedAccessView(UnorderedAccessView unorderedAccessView, int slot);unorderedAccessViewは演算シェーダーにセットするUnorderedAccessViewです。
public class UnorderedAccessView : ResourceView
public UnorderedAccessView(Device device, Resource resource);deviceはこのViewを持つデバイスです。
~Viewクラス | 説明 |
DepthStencilView | 深度ステンシルテストでテクスチャリソースとして使います。 |
RenderTargetView | レンダーターゲットなテクスチャーリソースとして使います。画面に映る描画先のことですね。 |
ShaderResourceView | シェーダーリソースとして使います。たとえば定数バッファ、テクスチャバッファ、テクスチャ、サンプラーなどです。演算シェーダーでも計算に必要なデータを格納したバッファをこれに指定することがあります。 |
UnorderedAccessView | ピクセルシェーダーか演算シェーダーで、複数のスレッドからのランダムアクセスっぽい読み書きを受け付ける、ということを意味します。 |
BindFlags = BindFlags.UnorderedAccess
BindFlagsの値 | 数値 | 説明 |
None | 0 | 特に何も指定しません。 |
VertexBuffer | 1 | 生成されるリソースが、Input Assemblerステージで、頂点バッファとして使えることを意味します。 |
IndexBuffer | 2 | 生成されるリソースが、Input Assemblerステージで、インデックスバッファとして使えることを意味します。 |
ConstantBuffer | 4 | 生成されるリソースが、シェーダーステージで、定数バッファとして使えることを意味します。 |
ShaderResource | 8 | 生成されるリソースが、シェーダーステージで、バッファやテクスチャとして使えるとうことを意味します。 |
StreamOutput | 16 | 生成されるリソースが、Stream Outputステージで、出力バッファとして使用できるということを意味します。Stream Outputステージとは頂点シェーダーとピクセルシェーダーステージの間に位置するステージの一つです。どうやらジオメトリーシェーダーとセットになっているらしく、新たな頂点データをメモリに書き出すことができます。 |
RenderTarget | 32 | 生成されるリソースが、Output Mergerステージで、レンダーターゲットとして使えることを意味します。つまり普通のDirectXアプリケーションで画面に表示される画像のことですね。 |
DepthStencil | 64 | 生成されるリソースが、Output Mergerステージで、深度ステンシルとして使えることを意味します。 |
UnorderedAccess | 128 | 生成されるリソースが、ランダムアクセス風に、複数のスレッドから同時に読み書きできることを意味します。 |
public static ShaderBytecode CompileFromFile( string fileName, string entryPoint, string profile, ShaderFlags shaderFlags, EffectFlags effectFlags );これはDirectX SDK付属のHLSLコンパイルツール、fxc.exeに似ています。
public class ComputeShader : DeviceChild
public ComputeShader(Device device, ShaderBytecode shaderBytecode);
public void Set(ComputeShader shader);shaderはデバイスにセットする演算シェーダーです。
public void Dispatch( int threadGroupCountX, int threadGroupCountY, int threadGroupCountZ );
numthreads(X, Y, Z)
演算シェーダーバージョン | Zの最大値 | スレッドの最大個数(X * Y * Z) |
cs_4_x | 1 | 768 |
cs_5_0 | 64 | 1024 |
T Operator[]( in uint indexPosition );
using System.Collections.Generic; using System.Linq; using SlimDX; using SlimDX.Direct3D11; using SlimDX.D3DCompiler; class Program { static void Main(string[] args) { Device device = new Device(DriverType.Hardware); Buffer onlyGpuBuffer = createStructuredBuffer(device, Enumerable.Range(0, 10).ToArray()); initComputeShader(device, onlyGpuBuffer); device.ImmediateContext.Dispatch(10, 1, 1); writeBuffer(device, onlyGpuBuffer); } static void initComputeShader(Device device, Buffer onlyGpuBuffer) { device.ImmediateContext.ComputeShader.SetUnorderedAccessView(new UnorderedAccessView(device, onlyGpuBuffer), 0); ShaderBytecode shaderBytecode = ShaderBytecode.CompileFromFile( "MyShader.fx", "MyComputeShader", "cs_4_0", ShaderFlags.None, EffectFlags.None ); device.ImmediateContext.ComputeShader.Set( new ComputeShader(device, shaderBytecode) ); } static void writeBuffer(Device device, Buffer buffer) { Buffer cpuAccessibleBuffer = createCpuAccessibleBuffer(device, Enumerable.Range(0, 10).ToArray()); device.ImmediateContext.CopyResource(buffer, cpuAccessibleBuffer); int[] readBack = readBackFromGpu(cpuAccessibleBuffer); foreach (var number in readBack) { System.Console.WriteLine(number); } } static Buffer createStructuredBuffer(Device device, int[] initialData) { DataStream initialDataStream = new DataStream(initialData, true, true); return new Buffer( device, initialDataStream, new BufferDescription { SizeInBytes = (int)initialDataStream.Length, BindFlags = BindFlags.UnorderedAccess, OptionFlags = ResourceOptionFlags.StructuredBuffer, StructureByteStride = sizeof(int) } ); } static Buffer createCpuAccessibleBuffer(Device device, int[] initialData) { DataStream initialDataStream = new DataStream(initialData, true, true); return new Buffer( device, initialDataStream, new BufferDescription { SizeInBytes = (int)initialDataStream.Length, CpuAccessFlags = CpuAccessFlags.Read, Usage = ResourceUsage.Staging } ); } static int[] readBackFromGpu(Buffer from) { DataBox data = from.Device.ImmediateContext.MapSubresource( from, MapMode.Read, MapFlags.None ); return getArrayInt32(data.Data); } static int[] getArrayInt32(DataStream stream) { int[] buffer = new int[stream.Length / sizeof(int)]; stream.ReadRange(buffer, 0, buffer.Length); return buffer; } }
RWStructuredBuffer<int> MyBuffer;
[numthreads(1, 1, 1)]void MyComputeShader( uint3 threadID : SV_DispatchThreadID ){MyBuffer[threadID.x] *= 2;}
0 2 4 6 8 10 12 14 16 182倍になりました!