Objective-C скорость рисования графики - PullRequest
1 голос
/ 10 февраля 2012

Я смотрю на экран, пиксель за пикселем. У меня работает этот код, но он медленный ... Я нахожу это очень и очень странным, так как тот же код, написанный на javascript, очень быстрый достаточно быстро, чтобы мне пришлось замедлить мой интервал, который вызывает это ...

Что мне нужно сделать, чтобы ускорить это как минимум в 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 1011 *

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;
            }
        }
    }
}

Информация о профиле

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 ]

4 голосов
/ 10 февраля 2012

Вызов метода fillRect NSBezierPath для рисования каждого пикселя безумен. Если вам нужно рисовать объекты по одному пикселю за раз, затем рисовать в своем собственном буфере, а когда он будет готов к отображению, , а затем , вы отправляете его в сильно ориентированную на векторную графику OS X с аппаратным ускорением на OpenGL система. Если вы не собираетесь использовать какие-либо из продвинутых примитивов рисования, предлагаемых Quartz, не делайте миллион вызовов Quartz за кадр. Если вы не хотите реализовывать блиттинг самостоятельно, используйте SDL или Allegro. Но вы должны подумать, нужно ли рисовать каждую букву попиксельно. Графическая система OS X очень хороша для компоновки изображений, так как это является ее основным назначением. И, кстати, почему вы не можете просто использовать обычные методы рендеринга текста и связывать в свой собственный файл шрифта?

3 голосов
/ 10 февраля 2012

Первое, что я хотел бы сделать, это профилировать ваш код и посмотреть, что занимает так много времени.Я предполагаю, что здесь потрачено много времени:

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

Если мое предположение верно, вы сможете набрать некоторую скорость, переключив шаблон с NSArray на обычный массив чисел C.

РЕДАКТИРОВАТЬ :

Теперь, когда я вижу профиль, я думаю, что мое предположение было правильным.Вы пытались переключиться на массивы C?

Если вы открыты для другого подхода к рендерингу шрифтов, см. эту статью об атласах текстур, она может дать вам несколько хороших идей.

1 голос
/ 10 февраля 2012

Я полностью согласен, что этот метод рисования - безумие. Скорее всего, есть лучший способ сделать это. Переключение отдельных пикселей растрового изображения с последующим вызовом одной текстуры связывания и одного рисования - это первое, что приходит на ум.

Предполагая, что вы не будете или не можете изменить этот алгоритм, исходя из вашей информации о профилировании, похоже, вы тратите все свое время на отправку сообщений. Первое, что я хотел бы сделать, чтобы ускорить его, - вытащить все в один уродливый монстр, вместо того, чтобы разбивать его на три части. Да, это уродливо и глупо, но оно эффективно осветит все сообщения, отправленные внутри цикла, и выполнит только логику.

РЕДАКТИРОВАТЬ:

Рисование в растровом контексте без 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);
}

объяснение того, что все это делает в руководстве Quartz2D

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...