RacorX2The main difference between RacorX and RacorX2 is the compilation of the vertex shader with NVASM. Whereas the first example compiles the vertex shader with D3DXAssembleShader() while the application starts up, RacorX2 uses a pre-compiled vertex shader. To add the NVIDIA vertex and pixel shader assembler, you have to do the following steps:
The output of NVASM in the build window of your Visual C/C++ IDE should look like this:
The vertex shader is provided in its own ASCII file called basic.vsh. After compilation a binary object file with the name basic.vso is created in the directory <shaders>:
Creating a Vertex ShaderBecause of the already compiled vertex shader, the creation of the vertex shader has to be done in a different way than in the previous example. This happens in the InitDeviceObjects() function: //shader decl DWORD dwDecl[] = { D3DVSD_STREAM(0), D3DVSD_REG(0, D3DVSDT_FLOAT3 ), // input register 0 D3DVSD_END() }; // loads a *.vso binary file, already compiled with NVASM and // creates a vertex shader if (FAILED(CreateVSFromCompiledFile (m_pd3dDevice, dwDecl,"shaders/basic.vso", &m_dwVertexShader))) return E_FAIL; CreateVSFromCompiledFile() opens and reads in the binary vertex shader file and creates a vertex shader. The source of this function can be found at the end of the file racorx.cpp in the RacorX2 directory: //---------------------------------------------------------------------------- // Name: CreateVSFromBinFile // Desc: loads a binary *.vso file that was compiled by NVASM // and creates a vertex shader //---------------------------------------------------------------------------- HRESULT CMyD3DApplication::CreateVSFromCompiledFile (IDirect3DDevice8* m_pd3dDevice, DWORD* dwDeclaration, TCHAR* strVSPath, DWORD* m_dwVS) { char szBuffer[128]; // debug output DWORD* dwpVS; // pointer to address space of the calling process HANDLE hFile, hMap; // handle file and handle mapped file TCHAR tempVSPath[512]; // temporary file path HRESULT hr; // error if( FAILED( hr = DXUtil_FindMediaFile( tempVSPath, strVSPath ) ) ) return D3DAPPERR_MEDIANOTFOUND; hFile = CreateFile(tempVSPath, GENERIC_READ,0,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0); if(hFile != INVALID_HANDLE_VALUE) { if(GetFileSize(hFile,0) > 0) hMap = CreateFileMapping(hFile,0,PAGE_READONLY,0,0,0); else { CloseHandle(hFile); return E_FAIL; } } else return E_FAIL; // maps a view of a file into the address space of the calling process dwpVS = (DWORD *)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); // Create the vertex shader hr = m_pd3dDevice->CreateVertexShader( dwDeclaration, dwpVS, m_dwVS, 0 ); if ( FAILED(hr) ) { OutputDebugString( "Failed to create Vertex Shader, errors:\n" ); D3DXGetErrorStringA(hr,szBuffer,sizeof(szBuffer)); OutputDebugString( szBuffer ); OutputDebugString( "\n" ); return hr; } UnmapViewOfFile(dwpVS); CloseHandle(hMap); CloseHandle(hFile); return S_OK; } DXUtil_FindMediaFile(), a helper function located in the framework file dxutil.cpp, returns the path to the already compiled vertex shader file. CreateFile() opens and reads the existing file: HANDLE CreateFile( LPCTSTR lpFileName, // file name DWORD dwDesiredAccess, // access mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // SD DWORD dwCreationDisposition, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to template file ); Its first parameter is the path to the file. The flag GENERIC_READ specifies read access to the file in the second parameter. The following two parameters are not used, because file sharing should not happen and the fourth parameter is not used, because the file should not be inherited by a child process. The fifth parameter is set to OPEN_EXISTING. This way, the function fails if the file does not exist. Setting the sixt parameter to FILE_ATTRIBUTE_NORMAL indicates, that the file has no other attributes. A template file is not used here, so the last parameter is set to 0. Please consult the Platform SDK help file for more information. CreateFileMapping() creates or opens a named or unnamed file-mapping object for the specified file: HANDLE CreateFileMapping( HANDLE hFile, // handle to file LPSECURITY_ATTRIBUTES lpAttributes, // security DWORD flProtect, // protection DWORD dwMaximumSizeHigh, // high-order DWORD of size DWORD dwMaximumSizeLow, // low-order DWORD of size LPCTSTR lpName // object name ); The first parameter is a handle to the file from which to create a mapping object. The file must be opened with an access mode compatible with the protection flags specified by the flProtect parameter. We have opened the file in CreateFile() with GENERIC_READ, therefore we use PAGE_READONLY here. Other features of CreateFileMapping() are not needed, therefore we set the rest of the parameters to 0. MapViewOfFile() function maps a view of a file into the address space of the calling process: LPVOID MapViewOfFile( HANDLE hFileMappingObject, // handle to file-mapping object DWORD dwDesiredAccess, // access mode DWORD dwFileOffsetHigh, // high-order DWORD of offset DWORD dwFileOffsetLow, // low-order DWORD of offset SIZE_T dwNumberOfBytesToMap // number of bytes to map ); This function only gets the handle to the file-mapping object from CreateFileMapping() and in the second parameter the access mode FILE_MAP_READ. The access mode parameter specifies the type of access to the file view and, therefore, the protection of the pages mapped by the file. More features are not needed, therefore the rest of the parameters are set to 0. CreateVertexShader() is used to create and validate a vertex shader. It takes the vertex shader declaration (which maps vertex buffer streams to different vertex input registers) in its first parameter as a pointer and returns the shader handle in the third parameter. The second parameter gets the vertex shader instructions of the binary code pre-compiled by a vertex shader assembler. With the fourth parameter you can force software vertex processing with D3DUSAGE_SOFTWAREPROCESSING. As in the previous example OutputDebugString() shows the complete error message in the output debug window of the Visual C/C++ IDE and D3DXGetErrorStringA() interprets all Direct3D and Direct3DX HRESULTS and returns an error message in szBuffer. SummarizeThis example showed the integration of NVASM to pre-compile a vertex shader and how to open and read a binary vertex shader file. |