Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[MacOS] Snelle graphics in Mac OS X

Pagina: 1
Acties:

  • Adion
  • Registratie: Januari 2001
  • Laatst online: 17:51
Sinds zeer kort heb ik een MacBook Pro, en hier wil ik natuurlijk ook op kunnen programmeren.
Ik heb ondertussen XCode geinstalleerd, en ben nu aan het kijken hoe ik het beste op een vlotte manier kan tekenen.
Wat ik wil is met een framerate van ongeveer 40 fps mijn programma opnieuw tekenen (bestaande uit een achtergrondplaatje, een hoop andere plaatjes die hierover worden getekend, wat tekst en een aantal objecten die ik zelf pixel per pixel wil tekenen)

Onder windows heb ik dit opgelost met "CreateDIBSection"
Met deze functie kan ik namelijk een bitmap in het geheugen maken, en heb ik een handle zodat ik deze bitmap op het scherm kan blitten, en ik kan door deze handle ook makkelijk de standaard windows gdi functies gebruiken om er text op te tekenen of delen van andere plaatjes over te kopieren.
Bovendien kan ik ook direct aan de byte array van deze bitmap, waardoor ik heel snel mijn eigen tekenfuncties kan gebruiken. (Zelfs m'n eigen BitBlt die gebruik maakt van memcpy's is op die manier sneller dan de standaard BitBlt)
Liefst zou ik dus iets gelijkaardigs doen onder Mac OS.

Na een hoop gegoogled te hebben en tutorials/documentatie hebben doorgenomen kom ik tot volgende oplossing:
-Een subklasse maken van NSView
-In initWithFrame een NSTimer starten die elke 1/40 seconde afgaat
Objective-C:
1
2
3
        float fps = 1. / 40.;
        timer = [ NSTimer scheduledTimerWithTimeInterval: fps target: self
            selector: @selector( singleStep: ) userInfo: nil repeats: YES ];

-Elke keer de timer afgaat de graphics een redraw aanvragen
Objective-C:
1
2
3
4
5
- (void ) singleStep: ( NSTimer * ) t
{
    doAnimation();
    [self setNeedsDisplay:YES];
}

-In redraw een nieuw plaatje tekenen
Objective-C:
1
2
3
4
5
6
- (void)drawRect:(NSRect)rect {
    CGRect destRect = CGRectMake(0, 0, 640, 480);
    CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
    
    refreshImage(context, destRect);
}


doAnimation() en refreshImage() heb ik beide in C geschreven omdat ik daar momenteel nog beter mee overweg kan dan met Objective-C, en omdat het de bedoeling is om later de C++ code die ik al heb zowel voor windows als voor Mac OS te kunnen gebruiken.

In de C code heb ik een stuk geheugen om een backbuffer bij te houden in 32-bit RGBA formaat:
code:
1
unsigned char testImage[width * height * 4];


In refreshImage zorg ik ervoor dat ik de eerste keer een CGContextRef aanmaak.
Ook maak ik een ImageRef aan zodat ik deze op het scherm kan tekenen.
C:
1
2
3
4
5
6
7
8
9
10
11
12
void refreshImage(CGContextRef dest, CGRect destRect)
{   
    if (contextReference == NULL) {
        contextReference = CGBitmapContextCreate(testImage, width, height, 8, width*4, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGImageAlphaNoneSkipLast);
    }
    
    imageReference = CGBitmapContextCreateImage(contextReference);
    
    CGContextDrawImage(dest, destRect, imageReference);
    
    CGImageRelease(imageReference);
}


In doAnimation() ga ik alle pixels af en geef deze elke frame een andere kleur.

Dit alles werkt perfect, maar vergt voor 640x480 wel 50% cpu usage, zonder dat er al iets bijzonders gebeurd. Dat is natuurlijk veel te veel om bruikbaar te zijn, dus ging ik op zoek naar de oorzaak.

-CGBitmapContextCreateImage slechts 1x uitvoeren ipv elke frame:
Hierdoor zat ik aan 30% cpu usage. Dit is dus een behoorlijk zware functie. Helaas is zo'n CGImageRef een kopie van de bitmap, en door deze functie er tussenuit te laten werd mijn animatie dus niet meer geupdate.
Voor zover ik heb kunnen vinden is het ook niet mogelijk om de geheugenbuffer van een CGImageRef zelf aan te passen.
-CGContextDrawImage weglaten: 22%. 1x een 640x480 bitmap blitten kost dus ook al 8% cpu
-doAnimation verwijderen: 16%. For lus over 640x480 pixels kost dus een 6%
-setNeedsDisplay 40x per seconde uitvoeren zonder verder iets opnieuw te tekenen kost dus 16%, wat mij dus erg veel lijkt

Full-screen een video in QuickTime bekijken kost overigens slechts 30%, dus het is wel duidelijk dat er snellere oplossingen moeten bestaan.
Heeft iemand hier misschien ervaring mee? Zoals gezegd werkt deze techniek dus prima op veel tragere windows machines, maar helaas heb ik nog geen Mac OS voorbeelden gevonden die iets gelijkaardigs doen.

OpenGL of Quartz 2D Extreme heb ik ook al even bekeken, maar nog niet geprobeerd. Volgens sommige bronnen zou dit ook niet zo goed gaan met een mindere grafische kaart (de gewone macbooks bijvoorbeeld). In dat geval zou het ook geen oplossing zijn.

Ik heb ook al gedacht aan Core Video, en dan zelf een video source aan te bieden (voor video werkt het aanbieden van pixelbuffers blijkbaar wel goed) maar daar lijkt de documentatie die ik tot nog toe gevonden heb ook erg beperkt van, en misschien is het ook wel overkill voor wat ik wil bereiken.

VirtualDJ 2024 - Fast Image Resizer - Instagram


  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Geen antwoord op je vraag, maar het feit dat QuickTime "goedkoop" een video kan tonen zegt natuurlijk niks over hoe snel jij zelf frames op je scherm kan tekenen. De frames in video zijn al "klaar", alleen uncompressen in een framebuffer plaatsen en klaar. Jij bent zelf "live" frames aan het tekenen, in software. Dat kost veel meer processing power.

De vraag zal met name zijn wat er hardware accellerated is/kan worden. OpenGL zal dat in principe kunnen. In hoeverre dat met andere/meer high-level functies zo is, zal afhangen van de runtime environment die je gebruikt.

"Any sufficiently advanced technology is indistinguishable from magic."


  • Adion
  • Registratie: Januari 2001
  • Laatst online: 17:51
Zonder de frames te tekenen (dus gewoon een 640x480 CGImage 40x per seconde op het scherm tekenen) kost me ook al 44%, dat is toch wel erg veel, zeker als ik zie dat ik dit in windows doe met waarschijnlijk slechts een paar procent cpu usage. (En GDI onder windows werkt voor zover ik weet ook zo goed als volledig in software)

Het decoderen van video is trouwens ook maar iets dat nog maar zeer recent in hardware versnelt wordt. Dat QuickTime dus een mpeg4 bestand kan decoderen en op het scherm toveren zegt me dus wel dat het zeker mogelijk is. Als ik eenmaal aan het tekenen ben zal het inderdaad van m'n eigen code afhangen hoe snel het gaat, maar voor ik daaraan kan beginnen heb ik natuurlijk wel een snelle basis nodig om de pixels op het scherm te krijgen.

Overigens ben ik ondertussen wel nog uitgekomen op libSDL, wat een cross-platform library lijkt te zijn voor een hele hoop multimedia-functies (waaronder 2d graphics)
Ik weet nog niet precies of het wat is (en ik zou nog steeds liever zelf leren hoe het dan precies moet) maar van wat ik in deze tutorial zie lijkt het allesinds vrij eenvoudig om rechtstreeks pixels in te vullen.
Het lijkt er wel op dat voor Mac achterliggend QuickDraw wordt gebruikt, maar dat dit eigenlijk in Leopard obsolete is en dus beter niet meer gebruikt wordt.

VirtualDJ 2024 - Fast Image Resizer - Instagram


  • PolarBear
  • Registratie: Februari 2001
  • Niet online
De API's van het OS gebruiken, zoals Quartz 2D Extreme.

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-11 14:21

LauPro

Prof Mierenneuke®

Die NSTimer en alle GUI elementen hebben natuurlijk een gigantische impact op de performance als je dergelijke snelheden wil bereiken.

Je kan daar beter inderdaad een toolkit als SDL voor gebruiken, het zal niet de snelste zijn maar het geeft wel veel portabiliteit. En voor zover ik weet zijn ze bezig om SDL op de Mac wat meer native te maken (dat ligt een klein beetje in het verlengde van de X11-soap). Plus je hebt meteen een hoop praktijkvoorbeelden.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


  • Adion
  • Registratie: Januari 2001
  • Laatst online: 17:51
Ok, Quartz 2D Extreme was ik inderdaad al naar aan het kijken, maar gaat dit zeker werken op gewone MacBooks (zonder snelle videokaart)?

NSTimer 40x per seconde laten afvuren kost minder als 0.1% cpu, dus dat is het probleem niet.
'Alle GUI elementen' bestaat uit een venster met 1 control die ik subclass, dus dat zou ook op zich niet het probleem mogen zijn he.

SDL ga ik vandaag ook maar eens proberen dan, hoewel ik wel benieuwd ben hoe die het dan voor elkaar zouden krijgen. Tenslotte hebben zij toch ook maar dezelfde mogelijkheden als ik.

VirtualDJ 2024 - Fast Image Resizer - Instagram


  • orillion
  • Registratie: April 2006
  • Laatst online: 17:28
Adion schreef op dinsdag 25 maart 2008 @ 11:07:
Ok, Quartz 2D Extreme was ik inderdaad al naar aan het kijken, maar gaat dit zeker werken op gewone MacBooks (zonder snelle videokaart)?

....
Quartz Extreme wordt alleen door sommige G4's niet ondersteund (oude Mac Mini en iBook bijv.), dat had je zelf ook kunnen vinden.

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 19-11 21:32
Als je Core Graphics gebruikt werkt het als het goed is op alle Apple hardware waar OSX op draait. Of alles hardware versneld is, dat hangt van het specifieke stukje hardware af.

Een goed boek over 2D proggen in Mac is deze: http://www.amazon.co.uk/Q...on-Graphics/dp/0321336631

Overigens, als je C beter ligt. Je kan altijd Core Graphics direct gebruiken, dat is een C API.

  • Stukfruit
  • Registratie: Oktober 2007
  • Niet online
Adion schreef op maandag 24 maart 2008 @ 12:30:(En GDI onder windows werkt voor zover ik weet ook zo goed als volledig in software)
Voor zover ik weet is de GDI pas sinds Vista (zo goed als?) helemaal in software. Video wordt nog steeds via de hardware gedaan.

Maar vertel eens, waarom 40 frames per seconde, is dat niet een erg zomaar uit de lucht gegrepen waarde?
(30 of zelfs 20 fps zou ook heel goed moeten kunnen, mits je je framerate stabiel houdt)

Dat zit wel Schnorr.


  • Adion
  • Registratie: Januari 2001
  • Laatst online: 17:51
Ok, SDL net geinstalleerd, de SDL Application template genomen, en daar wat code aan toegevoegd om stabiel 40x per seconde pixel per pixel de kleur te veranderen.
Hiermee zit ik aan 7% cpu usage, dat is dus al een heel pak beter dan 50%.

30 fps zou waarschijnlijk inderdaad ook nog wel gaan, bij 20 fps begon ik toch al te merken dat niet alles meer zo vloeiend beweegt, zelfs als de framerate zeer stabiel is.

Ik ga nog wat verder kijken naar het gebruik van OpenGL/Quartz Extreme, en ook naar SDL in OpenGL, maar op het eerste zicht ziet het er met SDL allesinds vrij goed uit.

VirtualDJ 2024 - Fast Image Resizer - Instagram


  • Adion
  • Registratie: Januari 2001
  • Laatst online: 17:51
Ondertussen al wat meer geprobeerd met OpenGL (heb kort SDL+OpenGL geprobeerd, maar zag dat OpenGL in Cocoa gebruiken eigenlijk niet veel moeilijker is, en me weer een afhankelijkheid van een library bespaard)

Eerste resultaat was ook 50% voor 640x480, 40fps, als ik gewoon een texture maak (nieuwe texture elke frame).
Na wat verder te zoeken blijkt het vrij belangrijk te zijn dat het formaat BGRA 32-bit is, en niet RGBA 32-bit, dat blijkt al wat aan performance te schelen.
Verder blijkt het ook mogelijk een aantal kopieer-acties tussen de verschillende lagen te besparen ( zie hier )

Met volgende code:
code:
1
2
3
4
5
6
7
8
        glEnable (GL_TEXTURE_RECTANGLE_ARB);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE);
        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
        glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
            0, GL_RGBA, 640, 480, 0, GL_BGRA,
            GL_UNSIGNED_INT_8_8_8_8_REV,
            pictureBuffer);

Kom ik nu aan een 20% cpu. pictureBuffer is gewoon een array van unsigned char's waar ik dus vrij in kan tekenen zoals ik wil.

Ik heb het gevoel dat het nog beter moet kunnen als ik bijvoorbeeld ook real-time video wil kunnen tonen in OpenGL, maar het begint er toch al op te lijken.
Vermits veel van de graphics die ik wil tekenen toch door gewone niet-updatende textures kunnen worden getekend denk ik dat OpenGL me daar toch ook nog wat extra voordeel kan geven vermits de videokaart zich dan met transparency enzo kan bezig houden.

VirtualDJ 2024 - Fast Image Resizer - Instagram

Pagina: 1