Microsoft DirectX11 Win32 Tutorial 2. Vertex Shader.

Started by
6 comments, last by XNobodyX 10 years, 2 months ago

//--------------------------------------------------------------------------------------
// File: Tutorial02.cpp
//
// This application displays a triangle using Direct3D 11
//
// http://msdn.microsoft.com/en-us/library/windows/apps/ff729719.aspx
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include <windows.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>
#include "resource.h"

using namespace DirectX;

//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
    XMFLOAT3 Pos;
};


//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE               g_hInst = nullptr;
HWND                    g_hWnd = nullptr;
D3D_DRIVER_TYPE         g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL       g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device*           g_pd3dDevice = nullptr;
ID3D11Device1*          g_pd3dDevice1 = nullptr;
ID3D11DeviceContext*    g_pImmediateContext = nullptr;
ID3D11DeviceContext1*   g_pImmediateContext1 = nullptr;
IDXGISwapChain*         g_pSwapChain = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11VertexShader*     g_pVertexShader = nullptr;
ID3D11PixelShader*      g_pPixelShader = nullptr;
ID3D11InputLayout*      g_pVertexLayout = nullptr;
ID3D11Buffer*           g_pVertexBuffer = nullptr;


//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();


//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing 
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow )
{
    UNREFERENCED_PARAMETER( hPrevInstance );
    UNREFERENCED_PARAMETER( lpCmdLine );

    if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
        return 0;

    if( FAILED( InitDevice() ) )
    {
        CleanupDevice();
        return 0;
    }

    // Main message loop
    MSG msg = {0};
    while( WM_QUIT != msg.message )
    {
        if( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        else
        {
            Render();
        }
    }

    CleanupDevice();

    return ( int )msg.wParam;
}


//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
    // Register class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof( WNDCLASSEX );
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
    wcex.hCursor = LoadCursor( nullptr, IDC_ARROW );
    wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
    wcex.lpszMenuName = nullptr;
    wcex.lpszClassName = L"TutorialWindowClass";
    wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
    if( !RegisterClassEx( &wcex ) )
        return E_FAIL;

    // Create window
    g_hInst = hInstance;
    RECT rc = { 0, 0, 640, 480 };
    AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
    g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 11 Tutorial 2: Rendering a Triangle",
                           WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,
                           nullptr );
    if( !g_hWnd )
        return E_FAIL;

    ShowWindow( g_hWnd, nCmdShow );

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DCompile
//
// With VS 11, we could load up prebuilt .cso files instead...
//--------------------------------------------------------------------------------------
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
	//CompileShaderFromFile( L"Tutorial02.fx", "VS", "vs_4_0", &pVSBlob );
    HRESULT hr = S_OK;

    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
    // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
    // Setting this flag improves the shader debugging experience, but still allows 
    // the shaders to be optimized and to run exactly the way they will run in 
    // the release configuration of this program.
    dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif

    ID3DBlob* pErrorBlob = nullptr;
    hr = D3DCompileFromFile( szFileName, nullptr, nullptr, szEntryPoint, szShaderModel, 
        dwShaderFlags, 0, ppBlobOut, &pErrorBlob );
    if( FAILED(hr) )
    {
        if( pErrorBlob )
        {
            OutputDebugStringA( reinterpret_cast<const char*>( pErrorBlob->GetBufferPointer() ) );
            pErrorBlob->Release();
        }
        return hr;
    }
    if( pErrorBlob ) pErrorBlob->Release();

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
    HRESULT hr = S_OK;

    RECT rc;
    GetClientRect( g_hWnd, &rc );
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    UINT createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT numDriverTypes = ARRAYSIZE( driverTypes );

    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };
	UINT numFeatureLevels = ARRAYSIZE( featureLevels );

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

    for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
    {
        g_driverType = driverTypes[driverTypeIndex];
        hr = D3D11CreateDeviceAndSwapChain( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
                                            D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );

        if ( hr == E_INVALIDARG )
        {
            // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
            hr = D3D11CreateDeviceAndSwapChain( nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
                                                D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
        }

        if( SUCCEEDED( hr ) )
            break;
    }
    if( FAILED( hr ) )
        return hr;

    // Obtain the Direct3D 11.1 versions if available
    hr = g_pd3dDevice->QueryInterface( __uuidof( ID3D11Device1 ), reinterpret_cast<void**>( &g_pd3dDevice1 ) );
    if ( SUCCEEDED(hr) )
    {
        (void)g_pImmediateContext->QueryInterface( __uuidof( ID3D11DeviceContext1 ), reinterpret_cast<void**>( &g_pImmediateContext1 ) );
    }

    // Create a render target view
    ID3D11Texture2D* pBackBuffer = nullptr;
    hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
    if( FAILED( hr ) )
        return hr;

    hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );
    pBackBuffer->Release();
    if( FAILED( hr ) )
        return hr;

    g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, nullptr );

    // Setup the viewport
    D3D11_VIEWPORT vp;
    vp.Width = (FLOAT)width;
    vp.Height = (FLOAT)height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pImmediateContext->RSSetViewports( 1, &vp );

    // Compile the vertex shader
    ID3DBlob* pVSBlob = nullptr;
    hr = CompileShaderFromFile( L"Tutorial02.fx", "VS", "vs_4_0", &pVSBlob );
    if( FAILED( hr ) )
    {
        MessageBox( nullptr,
                    L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
        return hr;
    }

	// Create the vertex shader
	hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader );
	if( FAILED( hr ) )
	{	
		pVSBlob->Release();
        return hr;
	}

    // Define the input layout
    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
	UINT numElements = ARRAYSIZE( layout );

    // Create the input layout
	hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
                                          pVSBlob->GetBufferSize(), &g_pVertexLayout );
	pVSBlob->Release();
	if( FAILED( hr ) )
        return hr;

    // Set the input layout
    g_pImmediateContext->IASetInputLayout( g_pVertexLayout );

	// Compile the pixel shader
	ID3DBlob* pPSBlob = nullptr;
    hr = CompileShaderFromFile( L"Tutorial02.fx", "PS", "ps_4_0", &pPSBlob );
    if( FAILED( hr ) )
    {
        MessageBox( nullptr,
                    L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
        return hr;
    }

	// Create the pixel shader
	hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader );
	pPSBlob->Release();
    if( FAILED( hr ) )
        return hr;

    // Create vertex buffer
    SimpleVertex vertices[] =
    {
        XMFLOAT3( 0.0f, 0.5f, 0.5f ),
        XMFLOAT3( 0.5f, -0.5f, 0.5f ),
        XMFLOAT3( -0.5f, -0.5f, 0.5f ),
    };
    D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof(bd) );
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( SimpleVertex ) * 3;
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof(InitData) );
    InitData.pSysMem = vertices;
    hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
    if( FAILED( hr ) )
        return hr;

    // Set vertex buffer
    UINT stride = sizeof( SimpleVertex );
    UINT offset = 0;
    g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

    // Set primitive topology
    g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
    if( g_pImmediateContext ) g_pImmediateContext->ClearState();

    if( g_pVertexBuffer ) g_pVertexBuffer->Release();
    if( g_pVertexLayout ) g_pVertexLayout->Release();
    if( g_pVertexShader ) g_pVertexShader->Release();
    if( g_pPixelShader ) g_pPixelShader->Release();
    if( g_pRenderTargetView ) g_pRenderTargetView->Release();
    if( g_pSwapChain ) g_pSwapChain->Release();
    if( g_pImmediateContext1 ) g_pImmediateContext1->Release();
    if( g_pImmediateContext ) g_pImmediateContext->Release();
    if( g_pd3dDevice1 ) g_pd3dDevice1->Release();
    if( g_pd3dDevice ) g_pd3dDevice->Release();
}


//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch( message )
    {
        case WM_PAINT:
            hdc = BeginPaint( hWnd, &ps );
            EndPaint( hWnd, &ps );
            break;

        case WM_DESTROY:
            PostQuitMessage( 0 );
            break;

        default:
            return DefWindowProc( hWnd, message, wParam, lParam );
    }

    return 0;
}


//--------------------------------------------------------------------------------------
// Render a frame
//--------------------------------------------------------------------------------------
void Render()
{
    // Clear the back buffer 
    g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, Colors::MidnightBlue );

    // Render a triangle
	g_pImmediateContext->VSSetShader( g_pVertexShader, nullptr, 0 );
	g_pImmediateContext->PSSetShader( g_pPixelShader, nullptr, 0 );
    g_pImmediateContext->Draw( 3, 0 );

    // Present the information rendered to the back buffer to the front buffer (the screen)
    g_pSwapChain->Present( 0, 0 );
}

I see that the Vertex Shader is compiled into byte code and stored in the variable declared as "ID3DBlob* pVSBlob". The first thing I notice is that the only file name referenced in the program seems to be "Tutorial02.fx" however there are two other files that are part of the project in a Shaders folder called "Tutorial02_PS.hlsl" and "Tutorial02_VS.hlsl". I am trying to determine still what is the purpose of the other two .hlsl files.

As well one of the main things that I find curious is the code of the "Tutorial02.fx" file itself:


//--------------------------------------------------------------------------------------
// File: Tutorial02.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
float4 VS( float4 Pos : POSITION ) : SV_POSITION
{
    return Pos;
}


//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( float4 Pos : SV_POSITION ) : SV_Target
{
    return float4( 1.0f, 1.0f, 0.0f, 1.0f );    // Yellow, with Alpha = 1
}

I've tried to reference Frank D. Lunas book but the code here is sufficiently different from the vertex shader example in Chapter 6 that I am having a little difficulty putting together what the vertex shader code is actually doing. I did find some helpful documentation in this regard:

http://msdn.microsoft.com/en-us/library/windows/desktop/hh968107(v=vs.85).aspx

Although still there are some differences. One is that in the documentation example an .hlsl file is used and in the Win32 sample from here:

http://code.msdn.microsoft.com/windowsdesktop/Direct3D-Tutorial-Win32-829979ef

a .fx file is used. While that may be a small change I am trying to why the example vertex shader in the documentation seems to be referencing a cbuffer while the example vertex shader in Tutorial2 seems to be calling out a float4 or more specifically what is the meaning of:


float4 VS( float4 Pos : POSITION ) : SV_POSITION
{
    return Pos;
}

and


float4 PS( float4 Pos : SV_POSITION ) : SV_Target
{
    return float4( 1.0f, 1.0f, 0.0f, 1.0f );    // Yellow, with Alpha = 1
}

I see that they are called out as a Vertex Shader and a Pixel shader but that does not really say enough to me that I feel like I understand at all the function of those two blocks exactly. Of particular interest to me is the meanings of:

"( float4 Pos : POSITION ) : SV_POSITION"

and

"( float4 Pos : SV_POSITION ) : SV_Target"

Thanks for any help on this...

Advertisement
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
float4 VS( float4 Pos : POSITION ) : SV_POSITION

That means : "Create a function called VS, that takes input:

variable Pos, type float4 with semantics POSITION.

Since 'float4 VS( float4 Pos : POSITION ) : SV_POSITION' function is a vertex shader that means that the InputLayout object (the one that describes the data into the vertex buffers) defined in the C++ will provide a data which has assigned semantics called 'POSITION'. Think of the semantics lika a string that is describing the variable usage.

So "float4 Pos : POSITION" means : look for a data that belongs to the vertex buffers that also has assignd semantics 'POSITION' and assign the value to the Pos variable.

Next the SV_POSITION means: The function will return a float4 variable that will be used as vertex position. All semantics that begin with 'SV_' are reserved to the pipeline and they have special meaning. SV_POSITION in that particular case means that the Projected vertex position is returned by the function. Later in the pixel shader you can define a variable with semantics SV_POSITION and use the interpolated value for some calculations.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx

There is no real difference between an .fx file or a .hlsl file its an extenstion, the internals of both files will just be a shader and that is loaded into the D3DBlob* pointer so it can be compiled to the runtime.\

You can actually read and/or write to SV_ vars as outline in the link imoogiBG provided, for example you can use the SV_VertexID to generate a screen alligned quad in the GS without having to provide actual vertex data.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

There is a *big* (ok not that big but still) difference between regular shaders and effects. First of all an Effect(*.fx) represents not only a single shader but a set of techniques and passes( technique is a set of passes and pass is a set of vertex + pixel +... shaders).

Also when using effects there are some *helpers*, such as it is possible to describe a sampler directly into the Effect file(something that is not possible using ordinary shaders).

So basicly effects are sets of shaders (passes) wraped in techniques. The Effects also provide some 'simplification' and structures that are not usable when compiling ordinary shader.

There is a *big* (ok not that big but still) difference between regular shaders and effects. First of all an Effect(*.fx) represents not only a single shader but a set of techniques and passes( technique is a set of passes and pass is a set of vertex + pixel +... shaders).

Also when using effects there are some *helpers*, such as it is possible to describe a sampler directly into the Effect file(something that is not possible using ordinary shaders).

So basicly effects are sets of shaders (passes) wraped in techniques. The Effects also provide some 'simplification' and structures that are not usable when compiling ordinary shader.

That's not exactly true the extension doesn't define what the file is to be honest and in this case the .fx file doesn't contain techniques or passes or any pipeline state changes, all it contains is shader code. And thus there is no difference between the extensions, heck I could even defien an effect in a .ps or .vs file, it depends on how you interprete these files that determine wheter the thing is an effect or not.

When actually talking about the difference between an effect and just a shader code file thats when your definition holds, I was simply talking about the files themselves, and I can add all of the shaders to one file and still create separate shaders in code from that one file.

Samplers are part of HLSL not part of the effect parsing, http://msdn.microsoft.com/en-us/library/windows/desktop/bb509644%28v=vs.85%29.aspx, and you can set on up in D3D9 and D3D10 and up in the shader code.

The sample code in this case isn't even using the effect system, very little tutorials use the effect system for D3D11.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

"That's not exactly true the extension doesn't define what the file is to be honest and in this case the .fx file doe"

My bad I was thinking that the example is using effects.

Samplers are part of HLSL not part of the effect parsing, http://msdn.microsoft.com/en-us/library/windows/desktop/bb509644%28v=vs.85%29.aspx, and you can set on up in D3D9 and D3D10 and up in the shader code.

Samplers are part of HLSL (the "sampler MySampler;" part), however, sampler state configuration (the "sampler_state = { MagFilter = LINEAR; }" part) only has an effect when compiled as FX. In fact, the stuff inside the {} will be ignored entirely when compiling just as HLSL even if it is erroneous (within reason). The link you cite is primarily referring to FX, though it does not clearly state such.

This can be illustrated as follows:


sampler s 
#ifdef SAMPLER_STATE
= sampler_state { MagFilter = LINEAR; }
#endif // SAMPLER_STATE
#ifdef ERROR_STATE
= sampler_state { ONLY_FX_WILL_COMPLAIN = ABOUT_THIS_ERROR; }
#endif // ERROR_STATE
;

float4 main() : COLOR0 { return tex2D(s, (0).xx); }

technique { pass { pixelshader = compile ps_3_0 main(); } }

---

When just compiling the pixel shader as HLSL, the contents of the sampler_state will not show up anywhere in the resulting binary and the sampler_state which contains errors will compile just fine.

>fxc /nologo /T ps_3_0 test.hlsl /Fo none.o
compilation succeeded; see none.o

>fxc /nologo /T ps_3_0 test.hlsl /DSAMPLER_STATE=1 /Fo state.o
compilation succeeded; see state.o

>fxc /nologo /T ps_3_0 test.hlsl /DERROR_STATE=1 /Fo error.o
compilation succeeded; see error.o

>FC /B none.o state.o
Comparing files none.o and STATE.O
FC: no differences encountered


>FC /B none.o error.o
Comparing files none.o and ERROR.O
FC: no differences encountered

But when compiling as FX, the two binaries will be different - as to be expected. And the version with errors will not compile at all.

>fxc /nologo /T fx_2_0 test.hlsl /Fo fx_none.o
compilation succeeded; see fx_none.o

>fxc /nologo /T fx_2_0 test.hlsl /DSAMPLER_STATE=1 /Fo fx_state.o
compilation succeeded; see fx_state.o

>fxc /nologo /T fx_2_0 test.hlsl /DERROR_STATE=1 /Fo fx_error.o
test.hlsl(6,19): ID3DXEffectCompiler: Unrecognized state 'ONLY_FX_WILL_COMPLAIN'
ID3DXEffectCompiler: There was an error initializing the compiler

compilation failed; no code produced

>FC /B fx_none.o fx_state.o
Comparing files fx_none.o and FX_STATE.O
FC: FX_STATE.O longer than fx_none.o

The bit on how to use D3DCompileFromFile just about saved my life. All the tutorials I could find where using D3DX and I had no idea what I was doing wrong with D3DCompileFromFile

This topic is closed to new replies.

Advertisement