Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

21

26.02.2007, 22:36

wie machst du das mit der Syncronisation? Weil eigentlich sollte die Leistung nicht so massiv einbrechen. Alternativ kannst du auch mal schauen ob ein paar "Sleep(0)" im LadeThread ein wenig Linderung schaffen.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

22

27.02.2007, 14:32

Synchronisation komm ich ohne critical sections aus, die meiste Arbeit übernimmt eine pipe. Beim Laden wird dann direkt ein Pointer mitgeliefert, der vom Hauptthread noch auf eine StdLOD-Texture (immer geladen) gesetzt wird, und dann vom Lade-Thread auf die fertig geladene Texture. Müsste keine Probleme geben, da eine Texture-Verwaltung dahintersteht. Ich weiß nicht ob Sleep(0) was hilft... denn im prinzip ist der Performanceeinbruch doch nur bei einer Funktion: D3DXLoadTextureFromFile...
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

23

27.02.2007, 14:36

hm, vielleicht läuft das befüllen der textur in D3DXCreateTextureFromFile() nicht so optimal ab (locken mit ungünstigen falgs etc.), sodass während dem laden hoher busverkehr auftritt. die frage ist, ob ein "verlagern" des datenverkehrs viel bringt (denn irgendwann muss die textur in den vram)...

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

24

27.02.2007, 14:40

Willst du mir damit sagen, dass der ganze Aufwand um das dynamische Laden durch den Thread UNNÜTZ gewesen ist???
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

25

27.02.2007, 14:43

nein, ich will sagen, dass es evtl. andere faktoren zu berücksichtigen gilt.
wie eben den erwähnten busverkehr, der bei größeren texturen sicher nicht ganz unwesentlich ist.
sowohl der lade als auch der render thread müssen über die selbe leitung mit der graka reden. wenn jetzt der lade thread die leitung ziemlich auslastet...
am schlimmsten wäre das sicher, wenn du im lade thread eine textur lockst, mit der gerade gearbeitet wird -> pipeline stall. in dem fall (ich denk aber nicht, dass das bei dir der fall ist) wäre der nutzen von multithreading vermutlich gleich 0 oder sogar drunter ;)

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

26

27.02.2007, 15:01

Nein, das ist nicht der Fall... soll ich mal den Code posten, oder kannst du mir so sagen, was ich ändern soll? weil so geht das wirklich nicht... :-S
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

27

27.02.2007, 15:03

^^ ich weis nicht was du ändern sollst. waren nur ein paar gedanken von mir ;)

wenn möglich poste mal den relevanten code (also wann/wo der thread erzeugt wird und was im thread so abläuft etc.).

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

28

27.02.2007, 15:43

Ok! Also hier wird der Thread und die Pipe erstellt:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
//Pipe erstellen

    if(!(::CreatePipe(&m_hPipeR, &m_hPipeW, NULL, NULL)))
        OG_ERROR(L"Pipe konnte nicht erstellt werden", OG_ERROR);

//Thread erstellen

    m_iQueueLength = 0;
    m_hThread = ::CreateThread(NULL, 0, TextureLoadingThread, &m_hPipeR, 0, &m_dwThreadID);
    ::SetThreadPriority(m_hThread, THREAD_PRIORITY_NORMAL);


Wenn ein neuer Auftrag reinkommt, wird jener in die Pipe geschrieben:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
ogResult CCache::LoadTexture(const UINT iSector, const UINT iLOD, IDirect3DTexture9** ppTexPointer)
{
    if(!m_bActive) return OG_CANCEL;

    //Im Falle von Vorausladen, ist der Texture-Pointer gleich NULL, dann wird direkt

    //in das 2D-Texture-Array geladen: Also für den Thread entspricht das einem 

    //ppTexPointer von &(m_pppTextures[iSector][iLOD]);

    if(ppTexPointer)
    {
        //Wenn die Texture bereits geladen worden ist, direkt richtigen Pointer einsetzten

        if(m_pppTextures[iSector][iLOD])
        {
            *ppTexPointer = m_pppTextures[iSector][iLOD];
            return OG_OK;
        }
        //Zwischenzeitlich niederauflösende Texture laden

        *ppTexPointer = m_pppTextures[iSector][m_iStdLOD];
    }
    else
    {
        //Wenn schon geladen, dann abbrechen, sonst Texture einfach vorrausladen!

        if(m_pppTextures[iSector][iLOD]) return OG_OK;
        else ppTexPointer = &(m_pppTextures[iSector][iLOD]);
    }

    //Über PIPE den Auftrag speichern... (APPENDING)

    DWORD dwBytesWritten = 0;
    SPipePackage Data = SPipePackage(iSector, iLOD, ppTexPointer);
    if(!(::WriteFile(m_hPipeW, &Data, sizeof(SPipePackage), &dwBytesWritten, NULL)) || 
       (dwBytesWritten != sizeof(SPipePackage)))
    {
        OG_ERROR(L"Daten konnten nicht in die Pipe geschrieben werden!", OG_ERROR);
    }

    ++m_iQueueLength;
    return OG_OK;
}


m_pppTextures ist ein 2D-Array mit TexturePointern, wobei gilt: [SektorAufDerMap][LOD_Stufe], höchste LOD ist 0, niederste zugleich auch StdLOD = 3!

==============================================

Wenn alle Aufträge abgeliefert worden sind, wird diese Funktion aufgerufen, sie startet ev. den Thread:

C-/C++-Quelltext

1
2
3
4
5
void                    WorkDownQueue()
    {
        //Einfach den Thread starten, wenn Aufträge vorhanden

        if(m_iQueueLength > 0) ::ResumeThread(m_hThread);
    }


==============================================

Und dies hier ist der Thread selbst!

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//LoadingThread

DWORD WINAPI TextureLoadingThread(void* pParam)
{
    const bool      bDebugOutput        = true;
    HANDLE          hPipe               = *(static_cast<HANDLE*>(pParam));
    SPipePackage    aData[500];
    wchar_t         awcMainPath[256]    = L"data\\textures\\planet1\\";

    while(true)
    {
        //Thread stoppen (solange nichts zu tun ist, soll er keine Performance rauben!)

        if(CCache::Instance().m_iQueueLength <= 0) ::SuspendThread(CCache::Instance().m_hThread);
        //Zwischenspeichern

        const UINT iRecordCount = CCache::Instance().m_iQueueLength;
        
        //Zuviele Records?

        if(iRecordCount > 500)
        {
            OG_WARNING(L"Zu viele Aufträge in der Queue, werden einfach ignoriert!");
            CCache::Instance().m_iQueueLength = 0;
            continue;
        }

        //Thread wurde wieder gestartet --> Pipe auslesen

        DWORD dwBytesRead   = 0;
        DWORD dwDataSize    = sizeof(SPipePackage) * iRecordCount;
        if(!(::ReadFile(hPipe, aData, dwDataSize, &dwBytesRead, NULL)) || (dwBytesRead != dwDataSize))
        {
            OG_WARNING(L"Pipe konnte nicht ausgelesen werden! Queue wird auf 0 gesetzt");
            CCache::Instance().m_iQueueLength = 0;
            continue;
        }
        
        //Alle Texturen nacheinander laden

        HRESULT hResult;
        for(UINT i = 0; i < iRecordCount; ++i)
        {
            if(!(aData[i].ppTexPointer))
            {
                OG_WARNING(L"Achtung! NULL-Pointer zum Texture-laden! Überspringe!");
                continue;
            }

            //Texture schon geladen?

            if(CCache::Instance().m_pppTextures[aData[i].iSector][aData[i].iLOD])
            {
                *(aData[i].ppTexPointer) = CCache::Instance().m_pppTextures[aData[i].iSector][aData[i].iLOD];
                continue;
            }

            //Dateinamen zusammenstellen

            wchar_t awcFileName[256] = L"";
            if(aData[i].iLOD != 0)
                ::swprintf_s(awcFileName, 255, L"%sCache\\%d_%d.png", awcMainPath, (aData[i].iSector + 1), aData[i].iLOD);
            else
                ::swprintf_s(awcFileName, 255, L"%s%d.png", awcMainPath, (aData[i].iSector + 1));

            //Texture laden

            if(FAILED(hResult = D3DXCreateTextureFromFileExW(ogDirect3D::Instance().GetD3DDevice(),
                                                             awcFileName,
                                                             D3DX_DEFAULT,
                                                             D3DX_DEFAULT,
                                                             1,
                                                             0,
                                                             D3DFMT_UNKNOWN,
                                                             D3DPOOL_MANAGED,
                                                             D3DX_DEFAULT,
                                                             D3DX_DEFAULT,
                                                             NULL,
                                                             NULL,
                                                             NULL,
                                                             &(CCache::Instance().m_pppTextures[aData[i].iSector][aData[i].iLOD]))))
            {
                //Fehler

                OG_ERROR_DIRECTX(L"D3DXCreateTextureFromFileEx()", hResult, OG_ERROR);
            }

            //TexturePointer kopieren (zur Verfügung stellen)

            *(aData[i].ppTexPointer) = CCache::Instance().m_pppTextures[aData[i].iSector][aData[i].iLOD];
        }

        //Queue länge um abgearbeitete Recs kürzen

        CCache::Instance().m_iQueueLength -= iRecordCount;

    }   //while(true)


    return 0;
}


==============================================

Wenn eine Texture eines bestimmten Sektors wieder freigegeben werden soll, wird das so gemacht:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//Texture wieder freigeben

ogResult CCache::UnloadTexture(const UINT iSector, const UINT iLOD, IDirect3DTexture9** ppTexPointer)
{
    if(((*ppTexPointer) == NULL) || (iLOD == m_iStdLOD))
    {
        //Auf Std Texture setzten

        (*ppTexPointer) = m_pppTextures[iSector][m_iStdLOD];
        return OG_OK;       //StdLOD kann NICHT freigegeben werden

    }

    //Texture freigeben

    OG_SAFE_RELEASE(m_pppTextures[iSector][iLOD]);

    //Auf Std Texture setzten

    (*ppTexPointer) = m_pppTextures[iSector][m_iStdLOD];

    return OG_OK;
}

//ODER


ogResult CCache::UnloadAllSectorTexture(const UINT iSector, IDirect3DTexture9** ppTexPointer)
{
    //Auf STd setzten

    (*ppTexPointer) = m_pppTextures[iSector][m_iStdLOD];

    //Alle Tex dieses Sektors freigeben

    for(UINT i = 0; i < m_iStdLOD; ++i)
    {
        OG_SAFE_RELEASE(m_pppTextures[iSector][i]);
    }

    return OG_OK;
}
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

Osram

Alter Hase

Beiträge: 889

Wohnort: Weissenthurm

Beruf: SW Entwickler

  • Private Nachricht senden

29

27.02.2007, 19:22

Texturladen ist langsam, ich habe im Prinzip das selbe Problem :(. Meine Vermutung ist einfach wie schon gesagt wurde dass das Laden so viele CPU Sekunden raubt dass die FPS stark und lange runter gehen müssen.

Wenn das stimmt gibt es nur 3 Möglichkeiten:
1. Weniger oder kleinere Texturen laden. Z.B. durch einen besseren Cache Algorithmus dass es seltener zu einem Load - Unload - Load für eine Textur kommt.
2. Irgendwie das Laden beschleunigen. Hat jemand Erfahrung ob eine selbst geschriebene DDS Lade Routine schneller als die von D3DX ist, z.B. wenn man auf gewisse Flexibilität/Funktionalität verzichtet?
3. Mit den benötigten CPU Sekunden leben, aber es irgendwie psychologisch geschickt machen, z.B. in der Anfangsphase laden, für geringe aber gleichmässige FPS sorgen, während des Ladens den User ablenken etc.

Ich gebe zu dass alle 3 Möglichkeiten nicht super versprechend sind. U.U. kommst Du um ein Herabschrauben der Qualität nicht drum rum.
"Games are algorithmic entertainment."

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

30

27.02.2007, 19:33

Also was ich mir auf jedenfall beim eigenen Laden vorstellen könnte wäre ein paar Sleep(0) einzubauen, das hilft aber wahrscheinlich nur dann was, wenn einem die CPU GPU Syncronisation, CPU Leistung und BUS Rate nicht von grundauf einen Strich durch die Rechnung macht.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Werbeanzeige