2012-02-10 15 views
1

ピクセル単位で画面に描画することを検討しています。私はこのコードが動作しているが、その遅い...私はこれは非常に奇妙なjavascriptで書かれた同じ種類のコードは超高速ですが見つかりました。私はこれを呼んで私の間隔を遅くしなければならないほど十分に速く...Objective-Cグラフィックスの描画速度

少なくとも2〜3回これをスピードアップできるようにするために何が必要ですか?

Objective-Cの

- (void)drawPixelAtX:(int)X atY:(int)Y 
{ 
    [NSBezierPath fillRect:NSMakeRect(X, self.frame.size.height - Y, 1, 1)]; 
} 


- (void)drawCharater:(int)charCode atX:(int)charX atY:(int)charY color:(NSColor*)color; 
{ 
    if (charCode >= [self.font count]) 
     return; 

    [color set]; 
    NSArray *template = [self.font objectAtIndex:charCode]; 
    for (int y = 0; y < 16; y++) { 
     for (int x = 0; x < 8; x++) { 
      if ([[template objectAtIndex:y*8+x] intValue] == 1) 
       [self drawPixelAtX:(charX * 8 + x) atY:(charY * 16 + y)+1]; 
     } 
    } 
} 


- (void)drawRect:(NSRect)dirtyRect 
{ 
    [NSGraphicsContext saveGraphicsState]; 
    for (int x=0; x < 80; x++) { 
     for (int y=0; y < 25; y++) { 
      AnsiScreenChar *c = [self.screen objectAtIndex:(y*80)+x]; 
      [c.bgColor set]; 
      [NSBezierPath fillRect:NSMakeRect(x*8, self.frame.size.height - ((y+1)*16), 8, 16)]; 
      [self drawCharater:c.data atX:x atY:y color:c.fgColor]; 
     } 
    } 
    [NSGraphicsContext restoreGraphicsState]; 
} 

javascriptの

function updateDisplay() { 
    var $this = $(this); 
    var data = $this.data('ansi'); 

    for (var i = 0, length1 = data.screen.length; i < length1; ++i) { 
     var a = data.screen[i]; // cache object 
     for (var j = 0, length2 = a.length; j < length2; ++j) { 
      if (a[j][4]) { 
       data.ctx.save(); 
       data.ctx.beginPath(); 
       data.ctx.rect(data.fontWidth * j, data.fontHeight * i, data.fontWidth, data.fontHeight); 
       data.ctx.clip(); 

       data.ctx.fillStyle = a[j][0]; 
       data.ctx.fillRect(data.fontWidth * j, data.fontHeight * i, data.fontWidth, data.fontHeight); 

       data.ctx.fillStyle = a[j][1]; 
       drawCharater.call(this, a[j][2], [j, i], 1); 
       data.ctx.restore(); 

       a[j][4] = false; 
      } 
     } 
    } 
} 

Profileing情報

Running Time Self  Symbol Name 
12371.0ms 21.8% 12371.0  objc_msgSend 
2612.0ms 4.6% 2612.0  CFNumberGetValue 
2446.0ms 4.3% 2446.0  _class_getInstanceSize 
1910.0ms 3.3% 1910.0  -[__NSArrayI objectAtIndex:] 
1482.0ms 2.6% 1482.0  _CFExecutableLinkedOnOrAfter 
1384.0ms 2.4% 1384.0  object_getIndexedIvars 
1350.0ms 2.3% 1350.0  -[AnsiView drawCharater:atX:atY:color:] 
1277.0ms 2.2% 1277.0  OSAtomicCompareAndSwap64Barrier$VARIANT$mp 
1270.0ms 2.2% 1270.0  ripl_BltShape 
1261.0ms 2.2% 1261.0  -[__NSCFNumber intValue] 
1185.0ms 2.0% 1185.0  CFRelease 
1047.0ms 1.8% 1047.0  CGSShmemGuardUnlock 
1005.0ms 1.7% 1005.0  ripr_Rectangles 

私はそれを取りますCFNumberGetValueはintValueコールを処理していますか?

答えて

3

私がやる最初のことは、あなたのコードをプロファイルし、何がすごく時間がかかるか見ることです。私の推測では、多くの時間をここで過ごしているということです。

[[template objectAtIndex:y*8+x] intValue] 

私の推測が正しければ、あなたは整数の通常のC配列にNSArrayからテンプレートを切り替えることによって、いくつかの速度を得ることができるはずです。

EDIT

今私は、プロファイルを参照することを、私は私の推測は正しかったと思います。 C配列に切り替えようとしましたか?

フォントをレンダリングする方法が異なる場合は、テクスチャマップのthis articleを参照してください。

+0

これはCALayerのでテクスチャアトラスを行う上で、より良い記事です私見http://mysterycoconut.com/blog/2011/01/cag1/ – slf

+0

@slfこの記事が私が投稿したものにどのようにリンクしているかは面白いです(実際にはリンクを見つけた方法です)。 – dasblinkenlight

+0

ha!私はそれに気づいていなかった – slf

4

各ピクセルを描画するためにNSBezierPathのfillRectメソッドを呼び出すことは狂っています。一度に1ピクセルずつ描画してから、独自のバッファに描画する必要がある場合は、として、高度にベクトル指向のハードウェアアクセラレーションOpenGLベースのグラフィックスシステムに送ります。 Quartzが提供する先進的な描画プリミティブを利用しない場合は、フレームごとに100万回の呼び出しを行う必要はありません。自分でブリッティングを実装しない場合は、SDLまたはAllegroを使用します。しかし、すべての文字をピクセル単位で描画する必要があるかどうかを実際に検討する必要があります。 OS Xのグラフィックスシステムは、主な目的であるので、画像を合成するのに非常に優れています。ちなみに、通常のテキストレンダリング方法を使用して、自分のフォントファイルにバンドルするだけの理由は何ですか?

+0

私は正確なフォントを見つけようとしましたができませんでした。私が見つけたフォントは、表示されると歪んでしまい、100%ピクセルには完全ではありません。私はむしろこれのために第三者libsを扱わないだろう。私はもともとNSBitmapImageRepをmuckingしていて、データを直接(setPixelではなく)更新していました。これはこれよりも100倍遅かったです。 – Justin808

+0

OS Xではピクセル精度のフォントレンダリングが可能です。Proggyフォントは、ターミナルや他のアプリケーションでうまく機能します。あなたのニーズに合ったフォントが見つからない場合は、FontForgeを使用してください。 – user57368

+0

@ user57368カスタムフォントの使用方法とバンドル方法の例やリンクを含めることができますか? – slf

1

私は、この方法が狂っていることに強く同意します。これを行うより良い方法がある可能性があります。ビットマップの個々のピクセルを切り替えると、単一のバインドテクスチャと単一の描画を呼び出すことが最初に思い浮かびます。

このアルゴリズムを変更したり、変更したりすることはできないと仮定すると、プロファイリング情報からメッセージを送信するすべての時間を費やしているように見えます。それをスピードアップするためにまずやるべきことは、それを3つに分割するのではなく、1つの醜いモンスターメソッドにすべてを引き込むことです。はい、それは醜いと愚かですが、効果的にループ内のすべてのメッセージを送信し、ロジックのみを実行するだろう。

EDIT:objc_messageSendなしのビットマップコンテキストに描画

...

CGContextRef MyCreateBitmapContext (int pixelsWide, 
          int pixelsHigh) 
{ 
    CGContextRef context = NULL; 
    CGColorSpaceRef colorSpace; 
    void *   bitmapData; 
    int    bitmapByteCount; 
    int    bitmapBytesPerRow; 

    bitmapBytesPerRow = (pixelsWide * 4);// 1 
    bitmapByteCount  = (bitmapBytesPerRow * pixelsHigh); 

    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);// 2 
    bitmapData = calloc(bitmapByteCount);// 3 
    if (bitmapData == NULL) 
    { 
     fprintf (stderr, "Memory not allocated!"); 
     return NULL; 
    } 
    context = CGBitmapContextCreate (bitmapData,// 4 
            pixelsWide, 
            pixelsHigh, 
            8,  // bits per component 
            bitmapBytesPerRow, 
            colorSpace, 
            kCGImageAlphaPremultipliedLast); 
    if (context== NULL) 
    { 
     free (bitmapData);// 5 
     fprintf (stderr, "Context not created!"); 
     return NULL; 
    } 
    CGColorSpaceRelease(colorSpace);// 6 

    return context;// 7 
} 

void DrawMyStuff() 
{ 
    CGRect myBoundingBox;// 1 

    myBoundingBox = CGRectMake (0, 0, myWidth, myHeight);// 2 
    myBitmapContext = MyCreateBitmapContext (400, 300);// 3 
    // ********** Your drawing code here ********** // 4 
    CGContextSetRGBFillColor (myBitmapContext, 1, 0, 0, 1); 
    CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 200, 100)); 
    CGContextSetRGBFillColor (myBitmapContext, 0, 0, 1, .5); 
    CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 100, 200)); 
    myImage = CGBitmapContextCreateImage (myBitmapContext);// 5 
    CGContextDrawImage(myContext, myBoundingBox, myImage);// 6 
    char *bitmapData = CGBitmapContextGetData(myBitmapContext); // 7 
    CGContextRelease (myBitmapContext);// 8 
    if (bitmapData) free(bitmapData); // 9 
    CGImageRelease(myImage); 
} 

explanation of what it's all doing in the Quartz2D guide

+0

URLやチュートリアルなどのサンプルがありますか?私はこれをより良いものに変えても構いませんが、私はNSBitmapImageRepを使いこなそうとしたように、遅いです... – Justin808

+0

私が話していることの良い例を見つけようとします。彼らは何の改善もなしに1つのモノリシックな方法に? – slf

関連する問題