Frage zu meiner DDrawScreenshot funktion



  • Erst einmal erklährung. Ich habe einen 3.2 Ghz P4 HT. Prince of Persia (The Sands of the Time... oder so) läuft bei mir flüssig.

    Ich habe jetzt eine Screenshot-Funktion geschrieben, die ein 1024*768*8
    (256 Farben) bild Fotographiert und in eine 24 bit Bitmap umwandelt. Da das etwa 2 sec gedauert hat, habe ich eine asm Funktion daraus gemacht. Es dauert jetzt "nur" 0.5 sec, in etwa.
    Da das Programm insgesamt ein Spiel wird, wirken sich diese 0.5 sec negativ aus. Ich kann mir bloß nicht erklären, warum das so lange dauert, da immerhin oben genannte Spiele bei mir flüssig laufen. (und das bei 1024 * 768 Pixeln).

    void SaveBmp24 ( int width, int height) 
    { 
    	int quantity = width*height; 
        int DataBytes = 3*quantity;
    	char BmpPath[512];
    	byte *Farben=(byte*)malloc(768);
    	int SubAdr=ZeilenBreite+1024;
    
    	LPBYTE pData;
    	pData=(LPBYTE)calloc(sizeof(byte),DataBytes);
    
    	//Header vorbereiten
        BITMAPFILEHEADER kFileHeader; 
        kFileHeader.bfType = 0x4d42;  // "BM" 
        kFileHeader.bfSize = 
            sizeof(BITMAPFILEHEADER) + 
            sizeof(BITMAPINFOHEADER) + 
            DataBytes; 
        kFileHeader.bfReserved1 = 0; 
        kFileHeader.bfReserved2 = 0; 
        kFileHeader.bfOffBits = 
            sizeof(BITMAPFILEHEADER) + 
            sizeof(BITMAPINFOHEADER); 
    
        BITMAPINFOHEADER kInfoHeader; 
        kInfoHeader.biSize = sizeof(BITMAPINFOHEADER); 
        kInfoHeader.biWidth = width; 
        kInfoHeader.biHeight = height; 
        kInfoHeader.biPlanes = 1; 
        kInfoHeader.biBitCount = 24; 
        kInfoHeader.biCompression = BI_RGB; 
        kInfoHeader.biSizeImage = 0; 
        kInfoHeader.biXPelsPerMeter = 0; 
        kInfoHeader.biYPelsPerMeter = 0; 
        kInfoHeader.biClrUsed = 0; 
        kInfoHeader.biClrImportant = 0; 
    
    	//Bitmap berechnen
    	lpDDPalette->GetEntries(0, 0, 256, palEntry);
    	LockVRAM();
    
    	for(int i=0;i<256;i++)
    	{
    		Farben[i]=palEntry[i].peBlue;
    		Farben[i+256]=palEntry[i].peGreen;
    		Farben[i+512]=palEntry[i].peRed;
    	}
    	_asm
    	{
    		//Adresse in den Video-RAM berechnen
    		mov  esi,VIO_RAM
    		mov  eax,ZeilenBreite
    		mov  ebx,767
    		mul  ebx
    		add  esi,eax
    		//Zieldata adressieren
            mov  edi,pData
    		//Die Daten mit den Farben adressieren
    		mov  ebx,Farben
    
    		xor  eax,eax		//eax löschen
    
    		mov  edx,768		//Schleifenzähler 0 laden
    _loop0:
    		mov  ecx,1024		//Schleifenzähler 1 laden
    
    _loop1:
    		push ebx			//ebx zunächst sichern
    
    		lodsb				//al laden
    		add  ebx,eax		//und zu ebx addieren (der rest von eax ist ja 0)
    		mov  al,[ebx]
    		stosb				//Schreiben
    		add  ebx,256
    		mov  al,[ebx]
    		stosb
    		add  ebx,256
    		mov  al,[ebx]
    		stosb
    		pop  ebx
    		loop _loop1
    
    		sub  esi,SubAdr		//Zeile darunter einlesen
    
    		dec  edx
    		jne   _loop0
    	}
    
    	UnlockVRAM();
    	lpDDPalette->SetEntries(0, 0, 256, palEntry);
    
    	sprintf(BmpPath,"%s%s",PathScreen,"Screenshot.bmp");
    	FILE *Bmp=fopen(BmpPath,"wb");
    
    	fwrite( &kFileHeader,sizeof(BITMAPFILEHEADER),1       ,Bmp); 
    	fwrite( &kInfoHeader,sizeof(BITMAPINFOHEADER),1       ,Bmp); 
    	fwrite( pData		,sizeof(byte)            ,DataBytes,Bmp);
    
    	fclose(Bmp); 
    	free(pData);
    
    	free(Farben);
    	Farben=0;
    }
    

    Der ASM-Abschnitt benötigt die 0.5 sec, wenn ich diesen raus nehme (per /.../, dauert das ganze eine Zeit, die kaum mehr der Rede wert ist.
    Woran lieght das?
    Ich hoffe, das ganze ist so halbwegs verständlich...


  • Mod

    naja, die funktion kann noch deutlich verbessert werden, aber das problem liegt vermutlich eher im speichertyp, von dem du liest.
    wo zeigt VIO_RAM hin?



  • @Camper: VIO_RAM zeigt auf ein DDRAW-Surface

    LPDIRECTDRAWSURFACE7 lpDDsBack;
        DDSURFACEDESC2  ddsd;
    	ZeroMemory(&ddsd,sizeof(ddsd));
    	ddsd.dwSize=sizeof(ddsd);
        if((lpDDsBack->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))!=DD_OK)
    		return FALSE;
    	VIO_RAM=(BYTE *)ddsd.lpSurface;
    

    Ich weiß micht inwiefern du dich mit DirectX beschäftigt hast, dürfte aber eigentlich zu verstehen sein.

    die funktion kann noch deutlich verbessert werden

    Geht noch zu Optimieren? Wie? (Ich geb zu, bin in ASM vielleicht noch nicht so weit...)

    Danke für alle Antworten, Gruß Streusselkuchen 🙂


Anmelden zum Antworten