Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Ich versuche aktuell ein Image file, dass ich bereits erfolgreich mit der DevIL Library als Image geladen habe als DX9 Textur zu verwenden. Allerdings scheiter ich beim Aufruf der D3DXCreateTextureFromFileInMemory und erhalte stehts die Meldung D3DXERR_INVALID_DATA. Das Image ist korrekt geladen, unter OpenGL kann ich problemlos auf die geladenen Daten zugreifen. Die Daten erhalte ich als const unsigned char* Referenz. Für die DirectX Funktion benötige ich die Größe der Daten, die hole ich mir zuvor per folgenden Aufruf nach dem Laden und setze sie am Image-Objekt:

Code: Alles auswählen

ILinfo ImageInfo;
iluGetImageInfo(&ImageInfo);
image->setDataSize(ImageInfo.SizeOfData);
Der Aufruf zum Mappen der DX Textur sieht wie folgt aus:

Code: Alles auswählen

// load an image for the texture using DevIL codec
brGraphics::brImageManager& imgMgr = brGraphics::brImageManager::getInstance();
boost::shared_ptr<brGraphics::brImage> image = imgMgr.getImage("data/textures/testTexture.png");

LPDIRECT3DTEXTURE9  texture = 0;
unsigned int size = image->getDataSize();

//try map immage to texture
hr = D3DXCreateTextureFromFileInMemory(d3ddev,
                                                                image->getImageData(),
                                                                size,
                                                                &texture);

if (FAILED(hr))
 {
     throw brCore::brIllegalStateException(
         "Couldn't create valid D3D9Texture!: " + std::string(DXGetErrorString9(hr)));
}

// set texture sampler infos
d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
OpenGL läufts bestens nach folgendem Schema:

Code: Alles auswählen

     // load an image for the texture
      brGraphics::brImageManager& imgMgr = brGraphics::brImageManager::getInstance();
      boost::shared_ptr<brGraphics::brImage> image = imgMgr.getImage("data/textures/testTexture.png");
    
      // create the texture
      GLuint texture[1];
      glGenTextures(1, &texture[0]);					

      // Typical Texture Generation Using Data From The Bitmap
      glBindTexture(GL_TEXTURE_2D, texture[0]);
      glTexImage2D(GL_TEXTURE_2D, 0, 3, image->getWidth(), image->getHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, image->getImageData());
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
Hat jemand Erfahrung mit diesem Mechanismus? Mache ich grundlegend etwas falsch? Auch Versuche den const unsigned char* in einen (LPVOID) Pointer zu
casten brachten keinen Erfolg ...
Benutzeravatar
Schrompf
Moderator
Beiträge: 5054
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Schrompf »

Hast Du denn wirklich eine Datei an der Speicherstelle liegen? Soweit ich weiß, lädt Devil die Bilddaten und gibt Dir die bereits fertig entpackten und aufbereiteten Pixeldaten zurück. Du müsstest dann mit CreateTexture() eine Textur erzeugen, locken und die Pixeldaten da reinkopieren.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Stimmt, daran hab ich garnicht mehr gedacht. Ist ewig her, dass ich mich mit DevIL auseinandergesetzt habe. Danke für den Schlag auf den
Hinterkopf, ich werde das mal ausprobieren ...
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Grmpf, irgendwie hab ich ein Problem beim Versuch die Textur zu locken, wobei der Debugger nicht einmal aus dem Aufruf der Lock Funktion
zurückkommt sondern dann irgendwann abschmiert oder ich ihn terminiere. Zwischendurch gibt es folgende Debugmeldung:
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!Direct3DCreate9Ex () (C:\Windows\system32\d3d9d.dll)
In d3d9!D3DPERF_SetOptions () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!Direct3DCreate9Ex () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!D3DPERF_SetOptions () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!Direct3DCreate9Ex () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!PSGPSampleTexture () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!Direct3DCreate9Ex () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!D3DPERF_SetOptions () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!PSGPSampleTexture () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
In d3d9!D3DPERF_SetOptions () (C:\Windows\system32\d3d9d.dll)
At C:\binrev\repository\binrevengine\branches\hellhound-dev\src\brRenderer\DirectX\demos\direct3D_9\d3d9Texture.cpp:354
Debugger finished with status 0
Folgenden Code führe ich aus um die Textur zu locken, nachdem ich sie erstellt habe:

Code: Alles auswählen

 hr = D3DXCreateTexture( d3ddev,
                            image->getWidth(),
                            image->getHeight(),
                            1,
                            D3DUSAGE_DYNAMIC,
                            D3DFMT_R5G6B5,
                            D3DPOOL_DEFAULT,
                            &texture );

    if (FAILED(hr))
    {
 	      throw brCore::brIllegalStateException(
          "Couldn't create empty D3D9Texture! " + std::string(DXGetErrorString9(hr)));
    }

    // Lock the texture and copy the pixel data into it
    D3DLOCKED_RECT lr;
    hr = texture->LockRect( 0, &lr, 0, 0 );        // --> Hier ist Ende
    if(FAILED(hr))
    {
         throw brCore::brIllegalStateException(
         "Unable to lock D3D9Texture! " + std::string(DXGetErrorString9(hr)));
    }
Hat jemand Erfahrung mit dem Kopieren von Pixeln in eine DX Textur? Alle Tutorials die ich finde laden eine Textur direkt
von einem File, ich möchte aber die separat geladenen Bildaten der Textur zuweisen ...
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Ok, das Problem habe ich in den Griff bekommen, lag an einem falschen Texturformat, wodurch DX in der DLL
beim Locken der Textur abgeschmiert ist. Mit folgendem Code kann ich nun locken und auch mappen, allerdings
bekomme ich murx angezeigt ...

Code: Alles auswählen

    LPDIRECT3DTEXTURE9  texture = 0;
    boost::shared_ptr<brGraphics::brImage> image = imgMgr.getImage("data/textures/testTexture.png");

    // determine texture pixel format
    D3DFORMAT dxPixelFormat = brRenderer::brD3D9Mapping::getDXPixelFormat(image->getPixelFormat());
    log << output(brLog::OUT_CON_LOG) << time << "Dx9 pixel format: " << brRenderer::brD3D9Mapping::getDXPixelFormatName(dxPixelFormat) << std::endl;

    // create empty texture
    hr = D3DXCreateTexture( d3ddev,
                            image->getWidth(),
                            image->getHeight(),
                            0,                   
                            D3DUSAGE_DYNAMIC,
                            dxPixelFormat,
                            D3DPOOL_DEFAULT,
                            &texture );

    if (FAILED(hr))
    {
 	  throw brCore::brIllegalStateException(
          "Couldn't create empty D3D9Texture! " + std::string(DXGetErrorString9(hr)));
    }

    // Lock the texture and copy the pixel data into it
    D3DLOCKED_RECT lr;
    hr = texture->LockRect( 0, &lr, 0, 0 );
    if(FAILED(hr))
    {
         throw brCore::brIllegalStateException(
         "Unable to lock D3D9Texture! " + std::string(DXGetErrorString9(hr)));
    }

    unsigned int dwBytes = lr.Pitch * image->getHeight();
    memcpy(lr.pBits, (LPVOID)image->getImageData(), dwBytes);

    // Unlock the texture
    hr = texture->UnlockRect(0);
    if(FAILED(hr))
    {
         throw brCore::brIllegalStateException(
          "Unable to unlock D3D9Texture! " + std::string(DXGetErrorString9(hr)));
    }

   // defining texture samplers
   d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
   d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
[img]
http://www.img-share.net/uploads/15636d ... ailure.jpg
[/img]

Ich finde keinen Fehler. Kann mir jemand weiterhelfen?
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von eXile »

Mir ist schleierhaft, wie du die Texturdaten kopierst:
MSDN hat geschrieben:When accessing surfaces directly, take care to stay within the memory allocated for the dimensions of the surface and stay out of any memory reserved for cache. Additionally, when you lock only a portion of a surface, you must stay within the rectangle you specify when locking the surface. Failing to follow these guidelines will have unpredictable results. When rendering directly into surface memory, always use the pitch returned by the IDirect3DSurface9::LockRect method. Do not assume a pitch based solely on the display mode. If your application works on some display adapters but looks garbled on others, this may be the cause of the problem.
Kopiere die Daten zeilenweise in die Textur, damit du nicht in den (durch den Pitch angegebenen) Bereich reinschreibst.
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Verstehe ich Dich richtig, ich soll über jeden Pixel iterieren und für jeden einzelnen Pixel den Memcopy Befehl ausführen?
Erzeugt das keinen Overhead?
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Krishty »

Du sollst über jede Zeile iterieren und dabei gefälligst den Pitch beachten.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Hmm, wer lesen kann ist klar im Vorteil ;) Ich habe einmal vesucht Eure Anweisungen umzusetzen. Sieht schon besser aus,
ist aber noch nicht korrekt: http://www.img-share.net/uploads/48828d ... ailure.jpg

Hier ist einmal der aktuelle Code zum kopieren der Pixeldaten:

Code: Alles auswählen

    // the number of bytes consumed by one row of the image
    unsigned int pitch = lr.Pitch;
    log << output(brLog::OUT_CON_LOG) << time << "Pitch: " << pitch << std::endl;

    //checksum to get the image bytes per pixel for a single row
    unsigned int byPP = (image->getBpp()/8) * image->getWidth();
    log << output(brLog::OUT_CON_LOG) << time << "Checksum: " << byPP << std::endl;

    if(pitch>byPP){

       // Precompute as much as possible
       int rows   = image->getHeight();
       int stride = byPP;

       for(int y=0; y<rows; y++){

          // Defintion of the destination where lr.pBits is the
          // pointer to the DX texture data
          BYTE* dst = (BYTE*)lr.pBits + lr.Pitch * y;

          // Defintion of the source where we read from
          BYTE* src = (BYTE*)image->getImageData() + stride * y;

          memcpy(dst, src, stride);
       }
    }
Wie man sehen kann gibt es nun einen undefinierten bereich, resultierend aus dem Unterschied des Pitch zu den
Bytes Per Pixel * Image width. Was ja auch logisch und korrekt ist wenn ich mir die Werte anschaue (Pitch 1024 vs.
checksum 768). Nur was ich nicht verstehe ist wieso DX hier einen größeren Wert reserviert und wie ich diesen
undefinierten Bereich vermeide.

Zudem ist die Grafik horizontal gespiegelt und die Farben sind auch nicht korrekt. Eigentlich müsste es so aussehen:
http://www.img-share.net/uploads/17575opengl.jpg
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Krishty »

Hellhound hat geschrieben:Nur was ich nicht verstehe ist wieso DX hier einen größeren Wert reserviert
Weil die GPU Texturen nur filtern kann, wenn die Daten ausgerichtet sind und umso effizienter, je runder wenn die Zeilengröße, in Bytes, ist. Und wenn das der Entwickler nicht fertiggebracht kriegt, muss es eben die Runtime bzw. der Treiber intern machen ;)
Hellhound hat geschrieben:und wie ich diesen undefinierten Bereich vermeide. Zudem ist die Grafik horizontal gespiegelt und die Farben sind auch nicht korrekt.
1. In welchem Format ist die Textur?
2. In welchem Format ist der Quellbereich?

Dieses Geraffel ist btw genau der Grund, warum ich 1) nur vollkommen GPU-taugliche Grafiken lade (in Ausmaß und Format) und 2) falls das nicht möglich ist, alle Bild-zu-Bild-Konvertierungen von einer Grafikbibliothek übernehmen lasse.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 5054
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Schrompf »

Sieht für mich aus, als hättest Du ein Subtexel-Offset in Deiner Speicherkopieraktion - Rot oder Blau des aktuellen Texels scheinen im vorherigen oder Folgetexel zu landen. Außerdem scheint irgendein Schritt Deines Texturladers die Textur auf die nächsthöhere Zweierpotenz aufzublasen, weswegen Du den schwarzen Rand neben der Grafik bekommst. Wie Krishty schon sagte: benutze nach Möglichkeit nur Grafiken, die wirklich direkt von der GPU als Textur benutzbar sind. Das heißt unter anderem, dass alle Grafiken eine Zweierpotenz breit und hoch sein sollten. Also z.B. 1024x256. Alternativ musst Du halt Deinen Texturerzeuger umbauen, so dass er wirklich die exakte Größe der Ausgangsgrafik als Textur anlegt. Dann kommt halt eine krumme Größe bei raus - mit allen Folgen für Performance, Kompatibilität und MipMapping, die das so mit sich bringt.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Krishty »

Für mich sieht das eher aus, als sei die Zieltextur RGBA und die Quelldaten seien RGB. Darum ist auch nach genau drei Vierteln der Zeile Schluss, und die vertauschten Kanäle würde es auch erklären. Ich wollte es nur nicht deutlich aussprechen, weil der Lerneffekt hin ist, wenn nun anfängt, einfach acht Bytes zwischenzupumpen.

Warum die Textur gespiegelt ist, ist auch wieder eine ganz andere Frage. So erscheint es mir z.B. perfekt valide, dass 0|0 links unten ist und 1|1 rechts oben – es sei denn für das Viereck sind andere Koordinaten angegeben, aber ohne die zu kennen, kann man einfach nichts sagen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Bei der Textur handelt es sich um eine PNG Textur, 256x256 im IL Format (PF_R8G8B8), die ich auf das entsprechend equivalente
DX Fomat (D3DFMT_R8G8B8) mappe.

Mit dem Ursprung muß ich mal prüfen, wenn ich mich richtig erinnere ich glaube den OpenGL Ursprung gesetzt zu haben,
d.h. linke untere Ecke als Ursprung. Das erklärt zumindes dann die Spiegelung. Danke für den Hinweis ...
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Krishty »

Ich weiß nicht, in welche Notation DevIL für seine Bilder benutzt, aber D3DFMT_R8G8B8 entspricht in Endianness-unabhängiger Notation B8G8R8. Da PNG seine Pixel als R8G8B8 speichert, ist u.U. ein Tausch vonnöten.
Achja – könntest du den Screenshot nochmal als PNG posten? Das Chroma-Sampling von JPEG macht es wirklich schwer, dort pixelgroße Farbverschiebungen zu erkennen …

Warum nur drei Viertel des Bildes ausgefüllt werden, kann ich nun aber immernoch nicht sagen. Geh nochmal ganz sicher, dass die Textur in D3DFMT_R8G8B8 ist.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Hellhound
Beiträge: 53
Registriert: 23.08.2010, 10:00
Wohnort: Braunschweig
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Hellhound »

Ich habe bei mir noch mal den Debug mode aktiviert um die genauen DevIL Informationen zu ziehen, die ich beim Laden erhalte.
Das Image wird wie folgt geladen:
brImage : data/textures/testTexture.png
- width : 256
- height : 256
- bpp : 24
- mipmaps : 0
- format : PF_R8G8B8
Wobei das obere Pixel Format von mir aus den DevIL Format: IL_RGB und den Tpyen: IL_UNSIGNED_BYTE
spezifiziert wird. Sollte so korrekt sein, läuft ja auch bestens für OpenGL.

Ich habe den Code für die Texturerzeugung auch noch mal fest auf den D3DFMT_R8G8B8 gesetzt, gibt
aber keinen Unterschied:

Code: Alles auswählen

    hr = D3DXCreateTexture( d3ddev,
                            image->getWidth(),
                            image->getHeight(),
                            0,                                            //Mipmaps level
                            D3DUSAGE_DYNAMIC,
                            D3DFMT_R8G8B8,                    //Pixelformat
                            D3DPOOL_DEFAULT,
                            &texture );
Habe auch mal nen JPG anstelle von PNG verwendet, gleiche resultat.

Aber die Spiegelung ist korrigiert, habe im Loader tatsächlich OpenGL Spezifika benutzt und
das Origin auf die linke untere Ecke spezifiziert gehabt....

Hier wie gewünscht das Renderresultat als PNG: http://www.img-share.net/uploads/56660d ... ailure.png
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Probleme bei Anwendung D3DXCreateTextureFromFileInMemory

Beitrag von Krishty »

Wenn das PNG R8G8B8 ist, ist deine Textur B8G8R8 – oder besser B8G8R8X8:
http://msdn.microsoft.com/en-us/library/bb172800 hat geschrieben:Format [in]
D3DFORMAT
Member of the D3DFORMAT enumerated type, describing the requested pixel format for the texture. The returned texture may be of a different format from that specified, if the device does not support the requested format. Applications should check the format of the returned texture to see if it matches the format requested.
D3DFMT_R8G8B8 wird nämlich von so ziemlich keiner Karte unterstützt. Fall gelöst, viel Spaß beim Byte-weisen kopieren ;) Denk daran, dass du aus RGB BGR1 machen musst.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten