-th visitor
前回に引き続きしまづさんです。眼帯むずかしい。

折角ロングスカートなんだからそこで果物とかもたせてみたいよね。ってコンセプトで描きました。持ってるのは果物じゃなくて、食玩(箱にしか見えないけど)ですが。
今回はスカートの影とかのラインで失敗してる感がひしひしと。このポーズ難しい…しかしオリジナルと見直してみるとスカート長すぎ、胸小さすぎで散々な出来。リトライしたいところです。
ところでばってんさんの日が近いんですよね。この構図で書けばよかったかなと思い始めているところです。いやリベンジの意味をこめて描こうかなというのが今回のタイトルの意です。
合計4拍手いただきました。ありがとうございます。
> しまずさんかわいい!
いいよね…しまづさんあざとくて。
今回はカメラでごまかしていますが、眼帯部分が苦手なので次回はうまく書きたいところです。
はじめはフィギュアじゃなくて実際の人を撮ってるモチーフだったのですがアレなのでやめました。
新年明けました。今年もよろしくお願いいたします。気が付けば1月ももう半分ですよ。怠けすぎている…
今年の1枚はローアングラーは伊達じゃないなしまづさん。
正月関係ない。
㌧
デッサン狂ってるし絵を説明している時点で駄目ですね、ハイ。

今年は生活環境が変わるのでどうなるやら分かりませんが、もっと絵を描いていきたい所です。
いい加減CUDA#(仮称)の解説記事でも書いておこうかなと。対象は#13, CUDA 4.0。ちなみにリンク先にも書いてありますが、CUDA#(仮称)とはC#からCUDA Cで書かれたCUDA Kernelを呼び出すライブラリです。
特に題材が思いつかなかったので、サンプルのtestプロジェクトを最小のコードにして解説します。
まずCUDA#(仮称)はソースコードで公開しているため、ビルドが必要ですが、これはここに書かなくてもわかるかと思いますので省略。現状Visual Studio 2008 Proで作成されています。未確認ですが、ライブラリをコンパイルすればVB等からも使えるかと思います。たぶん、おそらく。個人的にはライブラリプロジェクトを参照設定することを推奨します。
ということで、CUDA KernelをCUDA Cで書きます。
// text.cu
extern "C" __global__ void Test(int *A, int *B);
__global__
void Test(int *A, int *B) {
int i= blockIdx.x + blockDim.x * threadIdx.x;
B[i] = A[i] * 10;
}
内容はAのメモリ内容を10倍にしてBに格納するという単純なものです。グラフィックで見栄えが良いものはDirect3DやOpenGLとの連携が必要になりめどいので今回はパス。extern "C"で名前リンケージをCにして置かないとC++コードとしてコンパイルされるので前後によくわからない文字列がつきます。まぁその名前でも呼び出せるので実質問題はないといえば問題ないのですが、分かりにくいので私はC名前リンケージにしています。
> nvcc -ptx test.cu
nvccでptxとしてコンパイル。作成したptxはexeと同じディレクトリにおきます。(これは次のプログラムの仕様なので実際は好きな位置においてかまいません。)
// test.cs
using System;
using Azumaya.Cuda;
class Program {
unsafe static void Main(string[] args) {
using(var cc = new CuContext(0))
using(var ctx = cc.MakeCurrent()) {
string module = System.IO.Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"test.ptx");
using(var mod = ctx.LoadModule(module))
using(var memA = ctx.AllocateDeviceMemory(100 * sizeof(int)))
using(var memB = ctx.AllocateDeviceMemory(100 * sizeof(int)))
using(var memHost = ctx.AllocateHostMemory(100 * sizeof(int))) {
var func = mod.GetFunction("Test");
func.SetGridBlockSize(10, 10);
int* mem = (int*)memHost.Pointer.ToPointer();
for(int i = 0; i < 100; i++)
mem[i] = i;
memHost.Read(memA, memA.Size);
func.SetParam(memA.Pointer, memB.Pointer);
ctx.Launch(func);
ctx.Synchronize();
memB.Read(memHost, memB.Size);
for(int i = 0; i < 100; i++)
Console.WriteLine(mem[i]);
}
}
}
}
続いてC#コード。長いので抜き出して解説しています。
using Azumaya.Cuda;
CUDA#のクラスはAzumaya.Cuda配下にあるためusingしておきます。
using(var cc = new CuContext(0))
using(var ctx = cc.MakeCurrent()) {
CuContextはCUDAコンテキストクラスです。これを作成することでGPUにCUDAを使う旨を通知します。引数の0はGPUのindexで複数のGPUを使いたい方は適宜正しいindexを指定するようにしてください。CuContext.MakeCurrent()(仮称)でコンテキストをアクティブにします。戻り値はContextProxyクラスのインスタンスで、このインスタンスが有効な間CuContextを通して作成されているCUDAコンテキストが操作可能になります。このインスタンスをDispose()することでCUDAコンテキストはディアクティブになります。
using(var mod = ctx.LoadModule(module))
using(var memA = ctx.AllocateDeviceMemory(100 * sizeof(int)))
using(var memB = ctx.AllocateDeviceMemory(100 * sizeof(int)))
using(var memHost = ctx.AllocateHostMemory(100 * sizeof(int))) {
全てのCUDAオブジェクトはContextProxyから作成されるように設計されています。ContextProxy.LoadModule()でptxのロード、ContextProxy.AllocateDeviceMemory()でCUDAデバイス上のメモリの確保、ContextProxy.AllocateHostMemory()でホスト上のメモリの確保を行います。AllocateHostMemory()は別にMarshal.GlobalAlloc()などでもかまいません。ただこのメソッド経由で確保するとページロックメモリ上に配置されるためCUDAデバイスメモリとのメモリ転送が若干高速化されます。
var func = mod.GetFunction("Test");
func.SetGridBlockSize(10, 10);
int* mem = (int*)memHost.Pointer.ToPointer();
for(int i = 0; i < 100; i++)
mem[i] = i;
memHost.Read(memA, memA.Size);
func.SetParam(memA.Pointer, memB.Pointer);
CuModule.GetFunction()でCUDA Kernelの関数を取得します。今回は10x10のスレッドを起動させるためCuFunction.SetGridBlockSize()で10, 10を指定しています。続いてメモリの初期化、CuHostMemory.Read()でデバイス上にメモリ転送、CuFunction.SetParam()でCUDA Kernelの引数を設定という流れです。
ctx.Launch(func);
ctx.Synchronize();
ContextProxy.Launch()でCUDA Kernelを起動して、ContextProxy.Synchronize()で終了するまで待ちます。みたまま。
memB.Read(memHost, memB.Size);
for(int i = 0; i < 100; i++)
Console.WriteLine(mem[i]);
これもみたままですね。CuDeviceMemory.Read()でデバイス上のメモリをホスト側に戻します。ちなみにCuDeviceMemory.Write()もあるので好きなほうを使ってください。
今回はエラーチェックをしていませんが、CUDA#(仮称)は内部で全てのCUDA APIの戻り値をチェックしており、エラーが発生するとCuExceptionが投げられるようになっています。必要ならこの例外をcatchしてください。また、全てのCUDAオブジェクトはContextProxy経由で作成するのでまずはこのクラスを眺めてみると良いかと思います。以上CUDA#(仮称)の基本的な使い方でした。
この項目はそのうち別ページに移動させます。ええそのうち
著作権は方位記号が所持します。特に配布規約明示されていないリソースの無断転載は一切禁止します。配布規約が明示されている場合はそちらに従ってください。当サイトへのリンクは張るも切るもご自由に。ただし画像など*.php以外へのリンクは借りている鯖の規約に抵触する可能性があるため、ご遠慮ください。また、全てのリソースのアドレスは一切保障しません。なお、リファラにより逆リンクされる可能性があります。