2010-03-07 6 views
10

Tengo un "procesador de software" que estoy portando desde la PC al iPhone. ¿Cuál es la forma más rápida de actualizar manualmente la pantalla con un buffer de píxeles en el iphone? por ejemplo, en Windows, la función más rápida que he encontrado es SetDIBitsToDevice.manera más rápida de dibujar un búfer de pantalla en el iphone

No sé mucho sobre el iPhone, o las bibliotecas, y parece que hay tantas capas y diferentes tipos de elementos de interfaz de usuario, así que puede ser que necesite mucha explicación ...

por ahora Voy a actualizar constantemente una textura en OpenGL y renderizarla en la pantalla, dudo mucho que esta sea la mejor manera de hacerlo.

ACTUALIZACIÓN:

He probado el método de la textura del tamaño de pantalla OpenGL:

llegué 17fps ...

utilicé una textura de 512x512 (ya que tiene que ser una potencia de dos)

simplemente la llamada de

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

parecía más o menos re Es responsable de TODA la ralentización.

comentándolo, y dejando en todo mi software el código de la GUI, y la representación de la textura que ahora no se actualiza, resultó en 60fps, 30% de uso del procesador, y sin picos notables de la CPU.

tenga en cuenta que GetBuffer() simplemente devuelve un puntero al backbuffer de software del sistema GUI, no hay reorganización ni cambio de tamaño del búfer, tiene el tamaño y el formato adecuados para la textura, así que estoy bastante seguro de que la ralentización no tiene nada que ver con el procesador de software, que es una buena noticia, parece que si puedo encontrar una manera de actualizar la pantalla a 60, la renderización del software debería funcionar por el momento.

He intentado actualizar la llamada de textura con 512,320 en lugar de 512,512 esto fue extrañamente aún más lento ... corriendo a 10 fps, también dice que la utilización del renderizado es solo del 5% y todo el tiempo se desperdicia en una llamada a Untwiddle32bpp dentro de openGLES.

Puedo cambiar mi procesamiento de software para que se procese de forma nativa a cualquier formato de píxel, si resultara en un blit directo.

FYI, probado en un G2 2.2.1 iPod touch (así como un Iphone 3G en los esteroides)

ACTUALIZACIÓN 2:

acabo de terminar escribiendo el método CoreAnimation/gráficos, se ve bien, pero estoy un poco preocupado acerca de cómo actualiza la pantalla cada fotograma, básicamente abandonando el viejo CGImage, creando uno nuevo ... compruébalo en 'someRandomFunction' a continuación: ¿es esta la manera más rápida de actualizar la imagen? cualquier ayuda sería muy apreciada.

// 
// 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's CALayer's 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 
+0

Oye me encontré con este problema, también, ¿es la única solución para crear y destruir un CGImage cada fotograma? (intenté esto y es más lento que glTexsubimage). Parece que el objetivo del proveedor directo es que debe apuntar a ese búfer, por lo que si lo cambio, la imagen se actualizará. ¿Alguna ayuda en esto? –

+0

Pensé que el objetivo de usar CGDataProviderCreateDirect era el acceso directo a un búfer de píxeles, actualizado con CADisplayLink. Desafortunadamente, esto es terriblemente lento. ¿Alguna solución descubierta? – aoakenfo

Respuesta

11

La tienda de aplicaciones más rápida manera de hacerlo aprobado CPU sólo para gráficos 2D es crear un CGImage respaldado por un buffer usando CGDataProviderCreateDirect y asignar a un contents que la propiedad CALayer 's.

Para obtener los mejores resultados, utilice los tipos de mapa de bits kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little o kCGImageAlphaNone | kCGBitmapByteOrder32Little y el doble buffer para que la pantalla nunca se encuentre en un estado incoherente.

editar: esto debería ser más rápido que dibujar una textura OpenGL en teoría, pero como siempre, perfil para estar seguro.

edit2: CADisplayLink es una clase útil sin importar el método de composición que use.

+0

¿Sería esto lo suficientemente rápido para hacer un video de 24 fps? –

+0

@ St3fan: ¡Espero que sea lo suficientemente rápido como para hacer 60fps al menos! ¡Empiezo a tener la sensación de que los Api y SO del iPhone están aún más hinchados que los de Windows de escritorio! @rpetrich, gracias, lo intentaré. Casi no sé nada sobre el desarrollo de iphone, como el ect de cosas de la GUI, por lo que me puede llevar un tiempo, ¿pueden recomendarme una buena plantilla para usar para comenzar? Solo he usado el GL abierto. – matt

+0

Matt las API de iPhone son extremadamente agradables en comparación con Win32. Algunas cosas simplemente no son posibles con un código Cocoa de nivel más alto. Presente una solicitud de error con Apple si cree que esto necesita una mejor API de Cocoa. –

3

La forma más rápida es utilizar IOFrameBuffer/IOSurface, que son marcos privados.

Por lo tanto, OpenGL parece ser la única forma posible de aplicaciones AppStore.

+0

He actualizado la pregunta con los resultados del método opengl, no se ve bien. – matt

1

Quizás podría abstraer los métodos utilizados en el procesador de software a un sombreador GPU ... podría obtener un mejor rendimiento. Debería enviar los datos codificados de "video" como una textura.

+0

esta es una buena idea, desafortunadamente para mi caso, pero definitivamente para otros. – matt

0

Un método más rápido que CGDataProvider y glTexSubImage es usar CVOpenGLESTextureCache. El CVOpenGLESTextureCache le permite modificar directamente una textura OpenGL en la memoria de gráficos sin volver a cargarla.

que lo usaron para una vista de la animación rápida se puede ver aquí:

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

Es un poco difícil de usar y me encontré con que después de preguntar a mi propia pregunta acerca de este tema: How to directly update pixels - with CGImage and direct CGDataProvider

1

Solo para publicar mi comentario a la respuesta de @ rpetrich en forma de respuesta, diré en mis pruebas que encontré que OpenGL es la manera más rápida. Implementé un objeto simple (subclase UIView) llamado EEPixelViewer que hace esto de manera genérica, creo que debería funcionar para la mayoría de la gente.

Utiliza OpenGL para insertar píxeles en una amplia variedad de formatos (24bpp RGB, 32 bits RGBA y varios formatos YpCbCr) en la pantalla de la manera más eficiente posible. La solución alcanza 60 fps para la mayoría de los formatos de píxeles en casi todos los dispositivos iOS, incluidos los más antiguos. El uso es muy simple y no requiere ningún conocimiento de 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]; 

Repita los displayPixelBufferPlanes llaman para cada cuadro (que carga el búfer de píxeles a la GPU usando glTexImage2D), y eso es prácticamente todo lo que hay que hacer. El código es inteligente ya que trata de usar la GPU para cualquier tipo de procesamiento simple requerido, como permutando los canales de color, convirtiendo YpCbCr en RGB, etc.

También hay bastante lógica para cumplir con la escala usando el La propiedad contentMode de UIView, así que UIViewContentModeScaleToFit/Fill, etc. todo funciona como se esperaba.

Cuestiones relacionadas