FEATURE_LEVEL_x_xx abfrage üblich?

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

hallo zusammen,

ich verwende in meiner Framework-Klasse für DirectX 11 eine Abfrage, die sämtliche Feature-Level und Device-Typen durchläuft.
Dadurch erstellt mir das Programm automatisch immer ein Objekt mit den angaben, die die Hard- und Software zur Verfügung stellt.

Ist diese Abfrage üblich?

In vielen Quellcodes habe ich bereits gesehen, dass ich fest angebe, welches Feature-Level und welchen Device-Typen ich haben möchte.
Daher kam mir diese Frage auf.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von dot »

Was machst du mit der Information dann?
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

Sobald ich die Information habe, welches Feature_Level ( DX 11.0 / 10.1 / 10.0 ) beziehungsweise welcher Device_Typ ( Hardware / Software / WARP / Reference ) mein PC als maximal verfügbares supportet, erstelle ich auf grund dieser Information mein Direct3D-Device.

als Beispiel habe ich euch mal die Basisklasse aus dem Buch, wo ich das her habe gepostet :

Dx11DemoBase.h:

Code: Alles auswählen

/*
    Beginning DirectX 11 Game Programming
    By Allen Sherrod and Wendy Jones

    DirectX 11 Base Class - Used as base class for all DirectX 11 demos in this book.
*/


#ifndef _DEMO_BASE_H_
#define _DEMO_BASE_H_

#include<d3d11.h>
#include<d3dx11.h>
#include<DxErr.h>


class Dx11DemoBase
{
    public:
        Dx11DemoBase();
        virtual ~Dx11DemoBase();

        bool Initialize( HINSTANCE hInstance, HWND hwnd );
        void Shutdown( );

        virtual bool LoadContent( );
        virtual void UnloadContent( );

        virtual void Update( float dt ) = 0;
        virtual void Render( ) = 0;

    protected:
        HINSTANCE hInstance_;
        HWND hwnd_;

        D3D_DRIVER_TYPE driverType_;
        D3D_FEATURE_LEVEL featureLevel_;

        ID3D11Device* d3dDevice_;
        ID3D11DeviceContext* d3dContext_;
        IDXGISwapChain* swapChain_;
        ID3D11RenderTargetView* backBufferTarget_;
};

#endif
Dx11DemoBase.cpp:

Code: Alles auswählen

/*
    Beginning DirectX 11 Game Programming
    By Allen Sherrod and Wendy Jones

    DirectX 11 Base Class - Used as base class for all DirectX 11 demos in this book.
*/


#include"Dx11DemoBase.h"


Dx11DemoBase::Dx11DemoBase( ) : driverType_( D3D_DRIVER_TYPE_NULL ), featureLevel_( D3D_FEATURE_LEVEL_11_0 ),
                                d3dDevice_( 0 ), d3dContext_( 0 ), swapChain_( 0 ), backBufferTarget_( 0 )
{

}


Dx11DemoBase::~Dx11DemoBase( )
{
    Shutdown( );
}


bool Dx11DemoBase::Initialize( HINSTANCE hInstance, HWND hwnd )
{
    hInstance_ = hInstance;
    hwnd_ = hwnd;

    RECT dimensions;
    GetClientRect( hwnd, &dimensions );

    unsigned int width = dimensions.right - dimensions.left;
    unsigned int height = dimensions.bottom - dimensions.top;

    D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE, D3D_DRIVER_TYPE_SOFTWARE
    };

    unsigned int totalDriverTypes = ARRAYSIZE( driverTypes );

    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0
    };

    unsigned int totalFeatureLevels = ARRAYSIZE( featureLevels );

    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory( &swapChainDesc, sizeof( swapChainDesc ) );
    swapChainDesc.BufferCount = 1;
    swapChainDesc.BufferDesc.Width = width;
    swapChainDesc.BufferDesc.Height = height;
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
    swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = hwnd;
    swapChainDesc.Windowed = true;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;

    unsigned int creationFlags = 0;

#ifdef _DEBUG
    creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    HRESULT result;
    unsigned int driver = 0;

    for( driver = 0; driver < totalDriverTypes; ++driver )
    {
        result = D3D11CreateDeviceAndSwapChain( 0, driverTypes[driver], 0, creationFlags,
                                                featureLevels, totalFeatureLevels,
                                                D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
                                                &d3dDevice_, &featureLevel_, &d3dContext_ );

        if( SUCCEEDED( result ) )
        {
            driverType_ = driverTypes[driver];
            break;
        }
    }

    if( FAILED( result ) )
    {
        DXTRACE_MSG( "Failed to create the Direct3D device!" );
        return false;
    }

    ID3D11Texture2D* backBufferTexture;

    result = swapChain_->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&backBufferTexture );

    if( FAILED( result ) )
    {
        DXTRACE_MSG( "Failed to get the swap chain back buffer!" );
        return false;
    }

    result = d3dDevice_->CreateRenderTargetView( backBufferTexture, 0, &backBufferTarget_ );

    if( backBufferTexture )
        backBufferTexture->Release( );

    if( FAILED( result ) )
    {
        DXTRACE_MSG( "Failed to create the render target view!" );
        return false;
    }

    d3dContext_->OMSetRenderTargets( 1, &backBufferTarget_, 0 );

    D3D11_VIEWPORT viewport;
    viewport.Width = static_cast<float>(width);
    viewport.Height = static_cast<float>(height);
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
    viewport.TopLeftX = 0.0f;
    viewport.TopLeftY = 0.0f;

    d3dContext_->RSSetViewports( 1, &viewport );

    return LoadContent( );
}


bool Dx11DemoBase::LoadContent( )
{
    // Override with demo specifics, if any...
    return true;
}


void Dx11DemoBase::UnloadContent( )
{
    // Override with demo specifics, if any...
}


void Dx11DemoBase::Shutdown( )
{
    UnloadContent( );

    if( backBufferTarget_ ) backBufferTarget_->Release( );
    if( swapChain_ ) swapChain_->Release( );
    if( d3dContext_ ) d3dContext_->Release( );
    if( d3dDevice_ ) d3dDevice_->Release( );    

    backBufferTarget_ = 0;
    swapChain_ = 0;
    d3dContext_ = 0;
    d3dDevice_ = 0;
}
Quelle:
http://www.ultimategameprogramming.com/
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von kimmi »

Das macht in meinen Augen durchaus Sinn, sofern du mehrere Konfigurationen für verschiedene Leistungsprofile von PC's unterstützen möchtest. Das erfordert allerdings auch mehr Arbeit im Code.

Gruß Kimmi
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

ist auch ein hauptgrund, warum ich diese abfragen an informationen in meinem code erhalten lassen möchte.

mit dem mehraufwand kann ich dir nur recht geben. je nachdem, welche Kombination aus Feature- und Driver-Type erstellt wird, können durchaus Funktionen außer kraft gesetzt werden, die allerdings durch eine andere Kombination funktionalität hätte.

einen Vorteil in diesem Zusammenhang kann es mir allerdings liefern, dass ich eine abwärtskompatibilität der Hardware gegenüber sicherstellen kann.

Ich habe mir in diesem Zuge auch schon überlegt, dass beim starten meines Games, eine automatische Konfiguration vorgenommen wird. Was mir im oben genannten Fall die initialisierung der Base_Klasse abnehmen wird.
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von simbad »

Was noch eine Überlegung wert ist, ob man nicht für bestimmte Feature unterschiedliche Display Klassen definiert, die dann eben nur das verfügbare Subset nutzen.
Dabei geht es in erster Linie darum massenweise Featureabprüfungen im Code zu verhindern. Denn wenn du eine Schleife millionenfach durchläufst, dann können ein paar if().. abfragen einfluss auf die Speed haben.

Auch die Kombination von einzelnen Feature lassen sich besser integrieren.

Nur mal so als Idee.
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

als grundgedanken habe ich mir überlegt, dass ich jeder klasse als member-variable das Feature-Level mit übergebe. dadurch währe zwar eine redundanz an zu erstellenden klassen gegeben, allerdings würde es auch heißen, dass jeweils die klassen angesprochen werden, die eine funktionalität gewährleisten.

outsch... beim schreiben grad einen fehler entdeckt. ich schreibe einfach innerhalb einer klassendefinition funktionen für die verschiedenen Feature-Level... :-/

memo an mich: "erst denken... dann reden und handeln"
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von dot »

Ich würd wohl eher einmal den kompletten Renderpfad gegen einen Feature Level schreiben und dann einfach je nach Feature Level die jeweilige Implementierung instanzieren. Denn der Feature Level spielt ja eigentlich überall rein, sogar in den Shadercode. Mit ein paar ifs it's jedenfalls sicherlich nicht getan wenn man die unterschiedlichen Level wirklich nutzen möchte ;)
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

dot hat geschrieben:Ich würd wohl eher einmal den kompletten Renderpfad gegen einen Feature Level schreiben
mir ist noch nicht so ganz klar, wie du das meinst
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von simbad »

Na sowas wie ich es auch versucht habe zu schreiben.

Basisklasse: CDisplay

Abgeleitete Klassen CFeaturexxDisplay, CFeatureyyDisplay.

Beim Starten erzeugst du dann je nach FeatureSet eine die entsprechende Klasse und sparst dir in deinem Code die ständige Prüfung auf Featurexx und Featureyy
Matthias Gubisch
Establishment
Beiträge: 470
Registriert: 01.03.2009, 19:09

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von Matthias Gubisch »

IlikeMyLife hat geschrieben:
dot hat geschrieben:Ich würd wohl eher einmal den kompletten Renderpfad gegen einen Feature Level schreiben
mir ist noch nicht so ganz klar, wie du das meinst
Denke mal er meint damit dass du für jedes Featurelevel das du verwenden möchstest einen kompletten Renderer schreibst, und nicht nur einen Renderer in dem du mittels If-Abfragen unterscheidest welche Funktion du für das aktuelle Featurelevel aufrufen musst.

Vorteil an mehreren Renderern:
Du kannst für jedes Featurelevel besser optimieren und musst keine bösen Tricks machen um alles unter einen Hut zu bekommen, und du sparst dir zur Laufzeit einige Abfragen die auf die Performance gehen können

Nachteil ist natürlich dass du dann mehrere Versionen des Renderers pflegen und auf dem Aktuellen stand halten musst.

Von daher würd ich mir genau überlegen was es dir bringt wenn du die Featurelevels unterscheidest, und ob es dir den Mehraufwand wert ist.
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

ah danke :-)

jetzt leuchtet es mir ein.

Mag zwar eine schöne Sache sein, dass dynamisch ein mögliches Objekt je nach Feature-Level und Driver-Type erzeugt wird, allerdings war deine Idee mein knackpunkt, da ich bislang zwar funktionierenden Code für meinen PC geschrieben habe, allerdings auf anderen Rechnern es zu probleme kommen kann, sobald ich eine Kombination erwische, die nicht programmiert ist.

zur Zeit habe ich ja erst 3 ( Feature-Level ) hoch 2 ( Driver-Types ) die es zu behandeln gibt :-)

EDIT:
Es verspricht mir in sofern die Erweiterbarkeit, sobald ein neues Feature-Level auf dem Markt kommt, allerdings dafür noch keine Hardware vorhanden ist. Auf diese Weise kann auch in Zukunft gewährleistet werden, dass mein Spiel nicht nur Abwärtskompatibel, sondern auch leicht zu Debuggen ist.
simbad
Establishment
Beiträge: 132
Registriert: 14.12.2011, 14:30

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von simbad »

Man muss ja nicht für jede Kombination den Renderer Komplett neu schreiben.
Man kann zum Beispiel das ganze in Gruppen gestalten. Also einen Renderer mit einer Gruppe von Features, die sich leicht von einander Trennen lassen.
Hinzu kommt das du für bestimmte operation methoden schreiben kannst, die überlagert werden, wenn die Operation für einen Renderer völlig anders ist.
Wenn man die Operationen als inline deklariert, dann hast du dadurch auch keinen nennenswerten Performance Verlust. Es macht auch der Übersichtlichkeit halber Sinn das ein wenig in unterschiedliche Klassen zu kapseln. Ansonsten blickst du da irgendwann nicht mehr durch.

Und nichts ist schlimmer als Programm-Code, den man nach zwei Wochen nicht mehr versteht, weil er unstrukturiert ist. Und nachträglich aufarbeiten ist genauso wie neu schreiben. Meist ist dann neu schreiben sinnvoller, weil man dann auch wirklich alle Neuigkeiten umbaut.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von dot »

Die Feature Level gibts doch eben gerade erst damit du dich einfach auf einen gewissen Satz an Funktionalität verlassen kannst ohne alles mit irgendwelchen Caps-Abfragen zu pflastern. Und genau so würde ich an das Problem herangehen: Du suchst dir einen Feature Level gegen den du coden willst und schreibst dann einen kompletten Renderer der eben nur diese Funktionalität benutzt, ganz ohne irgendwelche ifs und so. Genau das is der Zweck von Feature Levels.
Auf D3D9 willst du deine Partikelsimulation evtl. auf der CPU ausführen, ober über entsprechende Tricks im PixelShader. Auf D3D10 Hardware willst du vielleicht die StreamOutput Stage dafür verwenden und auf D3D11 willst du es dann evtl. doch lieber zu einem ganz anderen Zeitpunkt im ComputeShader machen. Ein single-threaded Renderer für D3D9 Hardware ist einfach grundlegend anders aufgebaut als ein multi-threaded Renderer für D3D11 Hardware...
Code für D3D_FEATURE_LEVEL_9_x unterscheidet sich fundamental von Code für D3D_FEATURE_LEVEL_11_x. Zumindest wenn du die verschiedenen Feature-Level wirklich nutzen willst, ist das jedenfalls ganz sicher nicht mit ein paar ifs zu stemmen wenn du mich fragst.
IlikeMyLife hat geschrieben:EDIT:
Es verspricht mir in sofern die Erweiterbarkeit, sobald ein neues Feature-Level auf dem Markt kommt, allerdings dafür noch keine Hardware vorhanden ist. Auf diese Weise kann auch in Zukunft gewährleistet werden, dass mein Spiel nicht nur Abwärtskompatibel, sondern auch leicht zu Debuggen ist.
Ich behaupte mal, gerade was Erweiterbarkeit angeht, bietet der Ansatz mit einem austauschbaren Renderer wesentliche Vorteile.
Wenn du den Renderer einfach austauschen kannst, eröffnet das auch zumindest ein wenig die Möglichkeit, das Ding auf anderen Plattformen verfügbar zu machen, weil du z.B. einfach eine OpenGL Implementierung reinstecken kannst...
IlikeMyLife
Establishment
Beiträge: 212
Registriert: 08.05.2011, 09:59
Benutzertext: Feel Free

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von IlikeMyLife »

dot hat geschrieben:Ich behaupte mal, gerade was Erweiterbarkeit angeht, bietet der Ansatz mit einem austauschbaren Renderer wesentliche Vorteile.
Wenn du den Renderer einfach austauschen kannst, eröffnet das auch zumindest ein wenig die Möglichkeit, das Ding auf anderen Plattformen verfügbar zu machen, weil du z.B. einfach eine OpenGL Implementierung reinstecken kannst...
Das ist genau der Weg wo ich hin möchte. In erster Linie werde ich ohnehin auf dem Feature-Level ( Dx11.0 ) Coden, den mein eigener Rechner her gibt.

Bedarf an den niedrigeren beziehungsweise an anderen Feature-Leveln ist im allgemeinen ja nur, wenn sich auf einem anderem PC mit meiner Konfiguration keine möglichkeit bietet, das Spiel starten zu können um diese Schnittstelle dynamisch zu halten.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von dot »

IlikeMyLife hat geschrieben:
dot hat geschrieben:Ich behaupte mal, gerade was Erweiterbarkeit angeht, bietet der Ansatz mit einem austauschbaren Renderer wesentliche Vorteile.
Wenn du den Renderer einfach austauschen kannst, eröffnet das auch zumindest ein wenig die Möglichkeit, das Ding auf anderen Plattformen verfügbar zu machen, weil du z.B. einfach eine OpenGL Implementierung reinstecken kannst...
Das ist genau der Weg wo ich hin möchte.
Aber mit if Abfragen über den Feature Level wirst du dort imo nur sehr schwer hinkommen.
Benutzeravatar
Krishty
Establishment
Beiträge: 8246
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: FEATURE_LEVEL_x_xx abfrage üblich?

Beitrag von Krishty »

Definitiv.

Eine Renderer-Schnittstelle abstrahiert nicht bloß ein paar ifs. Sie abstrahiert auch keine Render States, Buffer-Objekte, o.Ä. – sie abstrahiert komplette Zeichenpfade und alles, was dafür nötig ist.

Stell dir beim Entwurf einfach vor, du wolltest einen D3D11-Renderer und einen Raytracer zugleich kapseln. Der Raytracer kennt keine Z-Buffer-States, Shader, Vertex Buffers und welches Feature Level eine GPU kennt, geht ihm am Hintern vorbei. Er kennt kaum mehr als die Objekte, die er zeichnen soll; umgekehrt kennt das Programm nicht die Geometriebeschreibungen (dies ist eine grüne Kugel mit Radius r / dies sind 3000 grüne Dreiecke mit den Indizes 0, 2, 3, …), die er dafür einsetzt.

Darum darf auch der D3D11-Renderer nicht mit mehr hantieren oder mehr preisgeben (erst recht nicht so Low-Level-Kram wie Feature Levels).
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten