Самый быстрый способ рисовать экранный буфер на iphone

У меня есть "программный рендерер", который я переношу с ПК на iPhone. какой самый быстрый способ вручную обновить экран с помощью буфера пикселей на iphone? например, в окнах самая быстрая функция, которую я нашел, - SetDIBitsToDevice.

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

пока я просто собираюсь постоянно обновлять текстуру в opengl и отображать ее на экране, я очень сомневаюсь, что это будет лучший способ сделать это.

UPDATE:

Я попробовал метод текстуры с разрешением экрана OpenGL:

Я получил 17 кадров в секунду...

Я использовал текстуру 512x512 (потому что она должна быть двух)

просто вызов

glTexSubImage2D(GL_TEXTURE_2D,0,0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE, baseWindowGUI->GetBuffer());

казался очень ответственным за ВСЕ замедление.

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

обратите внимание, что GetBuffer() просто возвращает указатель на программный backbuffer системы GUI, во всяком случае, нет никакого повторного звонка или изменения размера буфера, он должным образом отформатирован и отформатирован для текстуры, поэтому я достаточно уверен замедление не имеет ничего общего с программным рендерером, что является хорошей новостью. Похоже, если я смогу найти способ обновления экрана на 60, рендеринг программного обеспечения должен работать пока.

Я попытался сделать вызов текстуры обновления с 512,320, а не 512 512, это было странно еще медленнее... работая на скорости 10 кадров в секунду, также говорится, что использование рендеринга составляет всего 5%, и все время тратится впустую на вызов Untwiddle32bpp внутри openGLES.

Я могу изменить свой рендеринг программного обеспечения для рендеринга в любой формат изображения, если это приведет к более прямому blit.

fyi, протестированный на 2.2.1 ipod touch G2 (так же, как Iphone 3G на стероидах)

ОБНОВЛЕНИЕ 2:

Я только что закончил написание метода CoreAnimation/Graphics, он выглядит неплохо, но я немного беспокоюсь о том, как он обновляет экран в каждом кадре, в основном отбрасывая старый CGImage, создавая совершенно новый... проверьте его в разделе "someRandomFunction" ниже: это самый быстрый способ обновления изображения? любая помощь будет принята с благодарностью.

//
//  catestAppDelegate.m
//  catest
//
//  Created by User on 3/14/10.
//  Copyright __MyCompanyName__ 2010. All rights reserved.
//




#import "catestAppDelegate.h"
#import "catestViewController.h"
#import "QuartzCore/QuartzCore.h"

const void* GetBytePointer(void* info)
{
    // this is currently only called once
    return info; // info is a pointer to the buffer
}

void ReleaseBytePointer(void*info, const void* pointer)
{
    // don't care, just using the one static buffer at the moment
}


size_t GetBytesAtPosition(void* info, void* buffer, off_t position, size_t count)
{
    // I don't think this ever gets called
    memcpy(buffer, ((char*)info) + position, count);
    return count;
}

CGDataProviderDirectCallbacks providerCallbacks =
{ 0, GetBytePointer, ReleaseBytePointer, GetBytesAtPosition, 0 };


static CGImageRef cgIm;

static CGDataProviderRef dataProvider;
unsigned char* imageData;
 const size_t imageDataSize = 320 * 480 * 4;
NSTimer *animationTimer;
NSTimeInterval animationInterval= 1.0f/60.0f;


@implementation catestAppDelegate

@synthesize window;
@synthesize viewController;


- (void)applicationDidFinishLaunching:(UIApplication *)application {    


    [window makeKeyAndVisible];


    const size_t byteRowSize = 320 * 4;
    imageData = malloc(imageDataSize);

    for(int i=0;i<imageDataSize/4;i++)
            ((unsigned int*)imageData)[i] = 0xFFFF00FF; // just set it to some random init color, currently yellow


    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    dataProvider =
    CGDataProviderCreateDirect(imageData, imageDataSize,
                               &providerCallbacks);  // currently global

    cgIm = CGImageCreate
    (320, 480,
     8, 32, 320*4, colorSpace,
     kCGImageAlphaNone | kCGBitmapByteOrder32Little,
     dataProvider, 0, false, kCGRenderingIntentDefault);  // also global, probably doesn't need to be

    self.window.layer.contents = cgIm; // set the UIWindow CALayer contents to the image, yay works!

   // CGImageRelease(cgIm);  // we should do this at some stage...
   // CGDataProviderRelease(dataProvider);

    animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(someRandomFunction) userInfo:nil repeats:YES];
    // set up a timer in the attempt to update the image

}
float col = 0;

-(void)someRandomFunction
{
    // update the original buffer
    for(int i=0;i<imageDataSize;i++)
        imageData[i] = (unsigned char)(int)col;

    col+=256.0f/60.0f;

    // and currently the only way I know how to apply that buffer update to the screen is to
    // create a new image and bind it to the layer...???
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    cgIm = CGImageCreate
    (320, 480,
     8, 32, 320*4, colorSpace,
     kCGImageAlphaNone | kCGBitmapByteOrder32Little,
     dataProvider, 0, false, kCGRenderingIntentDefault);

    CGColorSpaceRelease(colorSpace);

    self.window.layer.contents = cgIm;

    // and that currently works, updating the screen, but i don't know how well it runs...
}


- (void)dealloc {
    [viewController release];
    [window release];
    [super dealloc];
}


@end

Ответ 1

Самый быстрый одобренный App Store способ сделать 2D-графику только для ЦП - создать CGImage, поддерживаемый буфером, используя CGDataProviderCreateDirect и назначить это свойству CALayer contents.

Для достижения наилучших результатов используйте типы растровых изображений kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little или kCGImageAlphaNone | kCGBitmapByteOrder32Little и двойной буфер, чтобы дисплей никогда не находился в противоречивом состоянии.

edit: это должно быть быстрее, чем рисовать текстуру OpenGL в теории, но, как всегда, профиль должен быть уверен.

edit2: CADisplayLink - полезный класс, независимо от того, какой метод компоновки вы используете.

Ответ 2

Самый быстрый способ - использовать IOFrameBuffer/IOSurface, которые являются частными фреймворками.

Таким образом, OpenGL, по-видимому, является единственным возможным способом для приложений AppStore.

Ответ 3

Возможно, вы могли бы абстрагироваться от методов, используемых в программном рендерере, в графическом чипе... может получить лучшую производительность. Вам нужно будет отправить закодированные "видео" данные в виде текстуры.

Ответ 4

Просто, чтобы опубликовать свой комментарий к ответу @rpetrich в форме ответа, я скажу, что в моих тестах я нашел OpenGL самым быстрым способом. Я реализовал простой объект (подкласс UIView) под названием EEPixelViewer, который делает это в целом настолько, что он должен работать для большинства людей, которых я думаю.

Он использует OpenGL, чтобы максимально эффективно использовать пиксели в самых разных форматах (24bpp RGB, 32-бит RGBA и несколько форматов YpCbCr). Решение обеспечивает 60 кадров в секунду для большинства пиксельных форматов почти на каждом устройстве iOS, включая более старые. Использование очень простое и не требует знаний OpenGL:

pixelViewer.pixelFormat = kCVPixelFormatType_32RGBA;
pixelViewer.sourceImageSize = CGSizeMake(1024, 768);
EEPixelViewerPlane plane;
plane.width = 1024;
plane.height = 768;
plane.data = pixelBuffer;
plane.rowBytes = plane.width * 4;
[pixelViewer displayPixelBufferPlanes: &plane count: 1 withCompletion:nil];

Повторите вызов displayPixelBufferPlanes для каждого кадра (который загружает буфер пикселей в GPU с помощью glTexImage2D), и это почти все, что ему нужно. Этот код является интеллектуальным в том смысле, что он пытается использовать графический процессор для любой простой обработки, такой как перестановка цветовых каналов, преобразование YpCbCr в RGB и т.д.

Существует также немного логики для оценки масштабирования с использованием свойства UIView contentMode, поэтому UIViewContentModeScaleToFit/Fill и т.д. все работает как ожидалось.

Ответ 5

Более быстрый метод, чем CGDataProvider и glTexSubImage, должен использовать CVOpenGLESTextureCache. CVOpenGLESTextureCache позволяет напрямую изменять текстуру OpenGL в графической памяти без повторной загрузки.

Я использовал его для быстрого просмотра анимации, которое вы можете увидеть здесь:

https://github.com/justinmeiners/image-sequence-streaming

Немного сложно использовать, и я наткнулся на него, задав свой вопрос по этой теме: Как напрямую обновлять пиксели - с помощью CGImage и прямого CGDataProvider