Warum dauert "D3D9Device->UpdateTexture" beim ersten mal so lange?



  • Ich habe zwei Texturen. Beide sind vollkommen identisch. Sie sind 2048x2048 Pixel groß und das Format ist A8R8G8B8. Eine Textur ist im Pool Default und eine im Pool Systemmem. Wenn ich nun UpdateTexture zum ersten mal aufrufe, dann dauert der Aufruf ca. zwei Sekunden. Alle weiteren Aufrufe dagegen dauern weniger als 100 ms (ich habe es nicht genau gemessen, aber es sind mehr als 10 Bilder pro Sekunde beim Rendern). Vor allen "Updates" führe ich ein LockRect auf den gesamten Bereich aus.

    Kennt jemand das Problem? Warum dauert das so lange? Und kann man das irgendwie beschleunigen?

    Ich bin darauf gekommen, als ich für meine 2048x2048 Textur den Pool Managed benutzt und festgestellt habe, daß es dort (auch) zwei Sekunden beim Erstellen dauert. Dann habe ich mir meinen eigenen Manager geschrieben um zu sehen, ob es am DirectX Manager liegt oder an etwas anderem, und so wie es aussieht, liegt es nicht am DirectX Manager.

    Mein System: Pentium 4 1.6 GHz, 512 MB RDRAM, GeForce4 Ti 4600, WinXP


  • Mod

    beim ersten mal stallst du die ganze renderpipe, danach ist sie schon gestallt und deswegen fällt das stallen weg und du bist fix.

    das beste mittel ist es nicht zu machen, jeder lock ist extrem schlecht für performance. deswegen sollte man vertex-, index- und texturebuffer auf keinen fall locken, besser ist wenn du nen anderen weg gehst (egal welcher, er sollte schneller sein als ein pipeline stall) und nur wenn es absolut nicht anders möglich ist, nur dann nen lock.

    das ist auch der grund weshalb gute engines, obwohl teile in einem einfach benchmark auf der cpu schneller wären als auf der graka (z.b. skinning auf nem 1.4ghz p4 ist schneller als auf einer gf3ti200), das trotzdem auf der graka machen, weil bei mehr als nur einem geskinnten objekt die graka sich ihre daten in den cache legen und besser abarbeiten kann und zudem keine speicherverfielfachung auftritt falls man ein und das selbe objekt mehrmals nutzt (nur mit anderen parametern), ein lock würde das cachen verhindern (und wie jeder weiß, können das oft über 5frames sein die im cache liegen).

    rapso->greets();



  • Vielen Dank für die Antwort, aber was hat die Renderpipe und das Stallen mit der Texturgröße zu tun? Wenn ich eine kleine Texturegröße nehme, dann gehts es ja fix, und es sollte doch für die Renderpipe egal sein, wie groß die Textur ist oder etwa nicht? Für mich sieht diese Verzögerung nach langen Berechnungen aus, welche mit der Textur durchgeführt werden; denn das Füllen bzw. Initialisieren von Speicher im Bereich von 30-50 MB (einmalg) sollte doch fixer gehen als in zwei Sekunden oder?

    Wird etwa bei einem "UpdateTexture" die Renderpipe gelöscht und neu intialisiert? Aber warum hängt dann dieses "Renderpipeupdate" mit der Texturgröße zusammen?

    😕


  • Mod

    es kommt ein wenig auf die flags an die du übergibst, bei sehr kleinen sachen die man lockt und writeonly hat, erstellt der treiber ein ganz neues objekt das gefüllt wird.

    aber auch da läuft der cache auch irgendwann über und ein stall tritt auf. wie gesagt, versuch es ohne lock zu lösen, dann klappt es besser.

    du müßtest mal ein bissl vom source zeigen damit man das besser analysieren kann.

    rapso->greets();



  • mir gehts hier mehr ums prinzip als um einen konkreten einzellfall in einem projekt, denn, wie soll ich eine textur mit daten füllen ohne lock und updatetexture? irgendwann muss die textur ja initialisiert werden. während dem rendern sollte man natürlich so gut wie nix locken, das ist klar, aber es gibt fälle wo man einfach nicht darum herum kommt, wie z.b. bei fonts (ok UserPointerDrawPrimitives wäre eine alternative, aber VB's mit locks sind schneller)

    mich nervt es, daß das updaten einer textur so lange dauert, und das nur beim ersten mal!

    quellcode aus meinem programm zu posten macht keinen sinn, da der effekt nicht durch komplizierten qode entsteht, sondern durch ein, ich nenne es mal, "DirectX-Problem" entsteht. du kannst den effekt ganz einfach nachsimulieren. ersetze in dem dx9 sdk tutorial "textures" die "InitGeometry" durch:

    HRESULT InitGeometry()
    {
    	g_pd3dDevice->CreateTexture(2048,2048,1,0,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&g_pTexture,0);
    	g_pd3dDevice->CreateTexture(2048,2048,1,0,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&g_pTexture2,0);
    
    	//g_pd3dDevice->UpdateTexture(g_pTexture2,g_pTexture);
    	//-> Text siehe unten
    
    /*
        // Use D3DX to create a texture from a file based image
        if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "banana.bmp", &g_pTexture ) ) )
        {
            // If texture is not in current folder, try parent folder
            if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "..\\banana.bmp", &g_pTexture ) ) )
            {
                MessageBox(NULL, "Could not find banana.bmp", "Textures.exe", MB_OK);
                return E_FAIL;
            }
        }
    */
        // Create the vertex buffer.
        if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),
                                                      0, D3DFVF_CUSTOMVERTEX,
                                                      D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
        {
            return E_FAIL;
        }
    
        // Fill the vertex buffer. We are setting the tu and tv texture
        // coordinates, which range from 0.0 to 1.0
        CUSTOMVERTEX* pVertices;
        if( FAILED( g_pVB->Lock( 0, 0, (void**)&pVertices, 0 ) ) )
            return E_FAIL;
        for( DWORD i=0; i<50; i++ )
        {
            FLOAT theta = (2*D3DX_PI*i)/(50-1);
    
            pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
            pVertices[2*i+0].color    = 0xffffffff;
    #ifndef SHOW_HOW_TO_USE_TCI
            pVertices[2*i+0].tu       = ((FLOAT)i)/(50-1);
            pVertices[2*i+0].tv       = 1.0f;
    #endif
    
            pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
            pVertices[2*i+1].color    = 0xff808080;
    #ifndef SHOW_HOW_TO_USE_TCI
            pVertices[2*i+1].tu       = ((FLOAT)i)/(50-1);
            pVertices[2*i+1].tv       = 0.0f;
    #endif
        }
        g_pVB->Unlock();
    
        return S_OK;
    }
    

    vorher aber noch "g_pTexture2" einfügen.

    wenn ich das update oben weglasse, dann geht es extrem schnell, wenn ich es wieder einbaue, dann dauert das update ca. zwei sekunden, aber das nur einmal. alle weiteren updates gehen dann relativ schnell, je nach lock, aber egal wieviel man lockt es ist dann beim zweiten und den folgenden malen schnell genug, um damit glücklich zu sein. nur das erste mal dauert es verdammt lange, und ich kann mir nicht vorstellen (bzw. es ist mir unverständlich, auch wenn es so ist wie du sagst), daß das was mit der renderpipe zu tun hat. sowas dauert doch keine zwei sekunden. damit etwas zwei sekunden dauert muss doch schon etwas berechnet werden, was sehr komplex ist, und ich könnte mir vorstellen, daß das was mit der textur selbst zu tun hat. Vielleicht werden da mipmaps generiert oder sowas änliches (auch wenn ich kein AUTOGENMIPMAP an habe).

    kleiner hinweis: "writeonly" geht bei textures nicht!


  • Mod

    dauert das wirklich 2 sekunden? 2sek wären ja selbst für nen stall noch happig lang in den meißten fällen.
    wenn du das bei der initialisierung machst, dann gibt es eh noch nichts zu stallen.
    wenn du ne binary machst die die zeit ausgibt wie lange es dauert, teste ich es gerne auf meinen grakas die gerade drinne sind.

    eigentlich müßten die 16MB die er da durch die gegend schiebt, selbst wenn er von der platte laden würde (was d3d wohl nicht macht) noch um einiges fixer sein.

    rapso->greets();

    ps

    D3DLOCK_DISCARD The application overwrites (with a write-only operation) every location within the locked surface. This is a valid option when using dynamic textures, dynamic vertex buffers, and dynamic index buffers. You may not use this option to update a portion of a surface.
    


  • VBS sind ja nun auch nicht ganz so groß, daher kann man dort doch ein paar mit den entsprechenden Flags dynamisch erzeugen. In der DXDoku ist auch genau beschrieben, welche Methode für welche Mengen vorgesehen ist.

    Ansonten könnte ich mir auch vorstellen, das beim Locken DX oder der Treiber seine Caching-Strategie ändert, wodurch dann großartige Kopieraktionen fällig werden. Allerdings nur eine Vermutung.

    Bye, TGGC (Zu viele Primitive hier.)



  • ich werde erst mal weiter mit den funktionen rumspielen und die sdk weiter doku studieren, bevor ich neues dazu sagen kann. momentan weiß ich nicht genau was ich noch machen könnte, nur eine möglichkeit ist mir eingefallen. wie gesagt, finde ich es seltsam, daß dieser rechenaufwand nur am anfang auftritt. deshalb werde ich versuchen das lange update bei allen updates zu erzwingen (falls das geht). vielleicht komm ich dann dem problem auf die spur.


Anmelden zum Antworten