Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1056 lines
32 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // The copyright to the contents herein is the property of Valve, L.L.C.
  4. // The contents may be used and/or copied only with the written permission of
  5. // Valve, L.L.C., or in accordance with the terms and conditions stipulated in
  6. // the agreement/contract under which the contents have been supplied.
  7. //
  8. // $Header: $
  9. // $NoKeywords: $
  10. //
  11. // Material editor
  12. //=============================================================================
  13. #include <windows.h>
  14. #include "appframework/tier2app.h"
  15. #include "shaderapi/ishaderdevice.h"
  16. #include "shaderapi/ishaderutil.h"
  17. #include "shaderapi/ishaderapi.h"
  18. #include "materialsystem/materialsystem_config.h"
  19. #include "materialsystem/imaterialsystemhardwareconfig.h"
  20. #include "vstdlib/random.h"
  21. #include "filesystem.h"
  22. #include "filesystem_init.h"
  23. #include "tier0/icommandline.h"
  24. #include "tier1/KeyValues.h"
  25. #include "tier1/utlbuffer.h"
  26. #include "tier1/lzmadecoder.h"
  27. #include "materialsystem/imesh.h"
  28. #include "materialsystem/shader_vcs_version.h"
  29. #include "../utils/bzip2/bzlib.h"
  30. class CShaderUtilTemp : public CBaseAppSystem< IShaderUtil >
  31. {
  32. public:
  33. // Method to allow clients access to the MaterialSystem_Config
  34. virtual MaterialSystem_Config_t& GetConfig()
  35. {
  36. static MaterialSystem_Config_t config;
  37. return config;
  38. }
  39. // Allows us to convert image formats
  40. virtual bool ConvertImageFormat( unsigned char *src, enum ImageFormat srcImageFormat,
  41. unsigned char *dst, enum ImageFormat dstImageFormat,
  42. int width, int height, int srcStride = 0, int dstStride = 0 )
  43. {
  44. return true;
  45. }
  46. // Figures out the amount of memory needed by a bitmap
  47. virtual int GetMemRequired( int width, int height, int depth, ImageFormat format, bool mipmap )
  48. {
  49. return 0;
  50. }
  51. // Gets image format info
  52. virtual const ImageFormatInfo_t& ImageFormatInfo( ImageFormat fmt ) const
  53. {
  54. static ImageFormatInfo_t info;
  55. return info;
  56. }
  57. // Allows us to set the default shadow state
  58. virtual void SetDefaultShadowState() { }
  59. // Allows us to set the default shader state
  60. virtual void SetDefaultState( ) { }
  61. // Bind standard textures
  62. virtual void BindStandardTexture( Sampler_t stage, StandardTextureId_t id ) { }
  63. virtual void BindStandardVertexTexture( VertexTextureSampler_t stage, StandardTextureId_t id ) { }
  64. virtual void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id ) { *pWidth = *pHeight = 0; }
  65. // What are the lightmap dimensions?
  66. virtual void GetLightmapDimensions( int *w, int *h ) { *w = *h = 0; }
  67. // These methods are called when the shader must eject + restore HW memory
  68. virtual void ReleaseShaderObjects() {}
  69. virtual void RestoreShaderObjects( CreateInterfaceFn shaderFactory, int nChangeFlags = 0 ) {}
  70. // Used to prevent meshes from drawing.
  71. virtual bool IsInStubMode() { return false; }
  72. virtual bool InFlashlightMode() const { return false; }
  73. // For the shader API to shove the current version of aniso level into the
  74. // "definitive" place (g_config) when the shader API decides to change it.
  75. // Eventually, we should have a better system of who owns the definitive
  76. // versions of config vars.
  77. virtual void NoteAnisotropicLevel( int currentLevel ) {}
  78. // NOTE: Stuff after this is added after shipping HL2.
  79. // Are we rendering through the editor?
  80. virtual bool InEditorMode() const { return false; }
  81. // Gets the bound morph's vertex format; returns 0 if no morph is bound
  82. virtual MorphFormat_t GetBoundMorphFormat() { return 0; }
  83. virtual ITexture *GetRenderTargetEx( int nRenderTargetID ) { return 0; }
  84. // Tells the material system to draw a buffer clearing quad
  85. virtual void DrawClearBufferQuad( unsigned char r, unsigned char g, unsigned char b, unsigned char a, bool bClearColor, bool bClearAlpha, bool bClearDepth ) OVERRIDE {}
  86. #if defined( _X360 )
  87. virtual void ReadBackBuffer( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pData, ImageFormat dstFormat, int nDstStride ) {}
  88. #endif
  89. // Calls from meshes to material system to handle queing/threading
  90. virtual bool OnDrawMesh( IMesh *pMesh, int firstIndex, int numIndices ) { return false; }
  91. virtual bool OnDrawMesh( IMesh *pMesh, CPrimList *pLists, int nLists ) { return false; }
  92. virtual bool OnSetFlexMesh( IMesh *pStaticMesh, IMesh *pMesh, int nVertexOffsetInBytes ) { return false; }
  93. virtual bool OnSetColorMesh( IMesh *pStaticMesh, IMesh *pMesh, int nVertexOffsetInBytes ) { return false; }
  94. virtual bool OnSetPrimitiveType( IMesh *pMesh, MaterialPrimitiveType_t type ) { return false; }
  95. virtual bool OnFlushBufferedPrimitives() { return false; }
  96. virtual void SyncMatrices() {}
  97. virtual void SyncMatrix( MaterialMatrixMode_t ) {}
  98. virtual int MaxHWMorphBatchCount() const { return 0; }
  99. virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo )
  100. {
  101. pInfo->m_bIsEnabled = false;
  102. pInfo->m_nLookupCount = 0;
  103. pInfo->m_flDefaultWeight = 0.0f;
  104. }
  105. virtual void OnThreadEvent( uint32 threadEvent ) {}
  106. ShaderAPITextureHandle_t GetShaderAPITextureBindHandle( ITexture *pTexture, int nFrame, int nTextureChannel ) { return 0; }
  107. // Remove any materials from memory that aren't in use as determined
  108. // by the IMaterial's reference count.
  109. virtual void UncacheUnusedMaterials( bool bRecomputeStateSnapshots = false ) {}
  110. virtual MaterialThreadMode_t GetThreadMode( ) { return MATERIAL_SINGLE_THREADED; }
  111. virtual bool IsRenderThreadSafe( ) { return true; }
  112. };
  113. static CShaderUtilTemp g_pTemp;
  114. static IShaderDeviceMgr *g_pShaderDeviceMgr;
  115. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderUtilTemp, IShaderUtil,
  116. SHADER_UTIL_INTERFACE_VERSION, g_pTemp )
  117. //-----------------------------------------------------------------------------
  118. // Purpose: Warning/Msg call back through this API
  119. // Input : type -
  120. // *pMsg -
  121. // Output : SpewRetval_t
  122. //-----------------------------------------------------------------------------
  123. SpewRetval_t SpewFunc( SpewType_t type, const char *pMsg )
  124. {
  125. if ( Plat_IsInDebugSession() )
  126. {
  127. OutputDebugString( pMsg );
  128. if ( type == SPEW_ASSERT )
  129. return SPEW_DEBUGGER;
  130. }
  131. return SPEW_CONTINUE;
  132. }
  133. //-----------------------------------------------------------------------------
  134. // The application object
  135. //-----------------------------------------------------------------------------
  136. class CShaderAPITestApp : public CTier2SteamApp
  137. {
  138. typedef CTier2SteamApp BaseClass;
  139. public:
  140. // Methods of IApplication
  141. virtual bool Create();
  142. virtual bool PreInit( );
  143. virtual int Main();
  144. virtual void PostShutdown( );
  145. virtual void Destroy();
  146. virtual const char *GetAppName() { return "InputTest"; }
  147. virtual bool AppUsesReadPixels() { return false; }
  148. private:
  149. // Window management
  150. bool CreateAppWindow( const char *pTitle, bool bWindowed, int w, int h );
  151. // Sets up the game path
  152. bool SetupSearchPaths();
  153. // Waits for a keypress
  154. bool WaitForKeypress();
  155. // Displays information about all adapters
  156. void DisplayAdapterInfo();
  157. // Sets the video mode
  158. bool SetMode();
  159. // Creates really simple vertex + index buffers
  160. void CreateSimpleBuffers( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered );
  161. // Destroys the buffers
  162. void DestroyBuffers();
  163. // Creates shaders
  164. void CreateShaders( const char *pVShader, int nVBufLen, const char *pGShader, int nGBufLen, const char *pPShader, int nPBufLen );
  165. // Destroys the buffers
  166. void DestroyShaders();
  167. // DrawUsingShaders
  168. void TestColoredQuad( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered );
  169. // Tests dynamic buffers
  170. void TestDynamicBuffers();
  171. bool CreateDynamicCombos_Ver5( uint8 *pComboBuffer, bool bVertexShader );
  172. void LoadShaderFile( const char *pName, bool bVertexShader );
  173. HWND m_HWnd;
  174. IShaderAPI *m_pShaderAPI;
  175. IShaderDevice *m_pShaderDevice;
  176. IIndexBuffer *m_pIndexBuffer;
  177. IVertexBuffer *m_pVertexBuffer;
  178. VertexShaderHandle_t m_hVertexShader;
  179. GeometryShaderHandle_t m_hGeometryShader;
  180. PixelShaderHandle_t m_hPixelShader;
  181. };
  182. DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CShaderAPITestApp );
  183. //-----------------------------------------------------------------------------
  184. // Create all singleton systems
  185. //-----------------------------------------------------------------------------
  186. bool CShaderAPITestApp::Create()
  187. {
  188. SpewOutputFunc( SpewFunc );
  189. bool bIsVistaOrHigher = false;
  190. OSVERSIONINFO info;
  191. info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  192. if ( GetVersionEx( &info ) )
  193. {
  194. bIsVistaOrHigher = info.dwMajorVersion >= 6;
  195. }
  196. const char *pShaderDLL = CommandLine()->ParmValue( "-shaderdll" );
  197. if ( !pShaderDLL )
  198. {
  199. pShaderDLL = "shaderapidx10.dll";
  200. }
  201. if ( !bIsVistaOrHigher && !Q_stricmp( pShaderDLL, "shaderapidx10.dll" ) )
  202. {
  203. pShaderDLL = "shaderapidx9.dll";
  204. }
  205. AppModule_t module = LoadModule( pShaderDLL );
  206. if ( module == APP_MODULE_INVALID )
  207. {
  208. if ( module == APP_MODULE_INVALID )
  209. {
  210. pShaderDLL = "shaderapidx9.dll";
  211. module = LoadModule( pShaderDLL );
  212. if ( module == APP_MODULE_INVALID )
  213. {
  214. pShaderDLL = "shaderapiempty.dll";
  215. module = LoadModule( pShaderDLL );
  216. if ( module == APP_MODULE_INVALID )
  217. return false;
  218. }
  219. }
  220. }
  221. g_pShaderDeviceMgr = (IShaderDeviceMgr*)AddSystem( module, SHADER_DEVICE_MGR_INTERFACE_VERSION );
  222. // So that shaderapi can get ahold of our bogus IShaderUtil
  223. module = LoadModule( Sys_GetFactoryThis() );
  224. AddSystem( module, SHADER_UTIL_INTERFACE_VERSION );
  225. return ( g_pShaderDeviceMgr != NULL );
  226. }
  227. void CShaderAPITestApp::Destroy()
  228. {
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Window callback
  232. //-----------------------------------------------------------------------------
  233. static LRESULT CALLBACK ShaderAPITestWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  234. {
  235. switch( message )
  236. {
  237. case WM_DESTROY:
  238. PostQuitMessage( 0 );
  239. break;
  240. default:
  241. return DefWindowProc( hWnd, message, wParam, lParam );
  242. }
  243. return 0;
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Window management
  247. //-----------------------------------------------------------------------------
  248. bool CShaderAPITestApp::CreateAppWindow( const char *pTitle, bool bWindowed, int w, int h )
  249. {
  250. WNDCLASSEX wc;
  251. memset( &wc, 0, sizeof( wc ) );
  252. wc.cbSize = sizeof( wc );
  253. wc.style = CS_OWNDC | CS_DBLCLKS;
  254. wc.lpfnWndProc = ShaderAPITestWndProc;
  255. wc.hInstance = (HINSTANCE)GetAppInstance();
  256. wc.lpszClassName = "Valve001";
  257. wc.hIcon = NULL; //LoadIcon( s_HInstance, MAKEINTRESOURCE( IDI_LAUNCHER ) );
  258. wc.hIconSm = wc.hIcon;
  259. RegisterClassEx( &wc );
  260. // Note, it's hidden
  261. DWORD style = WS_POPUP | WS_CLIPSIBLINGS;
  262. if ( bWindowed )
  263. {
  264. // Give it a frame
  265. style |= WS_OVERLAPPEDWINDOW;
  266. style &= ~WS_THICKFRAME;
  267. }
  268. // Never a max box
  269. style &= ~WS_MAXIMIZEBOX;
  270. RECT windowRect;
  271. windowRect.top = 0;
  272. windowRect.left = 0;
  273. windowRect.right = w;
  274. windowRect.bottom = h;
  275. // Compute rect needed for that size client area based on window style
  276. AdjustWindowRectEx(&windowRect, style, FALSE, 0);
  277. // Create the window
  278. m_HWnd = CreateWindow( wc.lpszClassName, pTitle, style, 0, 0,
  279. windowRect.right - windowRect.left, windowRect.bottom - windowRect.top,
  280. NULL, NULL, (HINSTANCE)GetAppInstance(), NULL );
  281. if (!m_HWnd)
  282. return false;
  283. int CenterX, CenterY;
  284. CenterX = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
  285. CenterY = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
  286. CenterX = (CenterX < 0) ? 0: CenterX;
  287. CenterY = (CenterY < 0) ? 0: CenterY;
  288. // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window.
  289. SetWindowPos (m_HWnd, NULL, CenterX, CenterY, 0, 0,
  290. SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  291. return true;
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Sets up the game path
  295. //-----------------------------------------------------------------------------
  296. bool CShaderAPITestApp::SetupSearchPaths()
  297. {
  298. if ( !BaseClass::SetupSearchPaths( NULL, false, true ) )
  299. return false;
  300. g_pFullFileSystem->AddSearchPath( GetGameInfoPath(), "SKIN", PATH_ADD_TO_HEAD );
  301. return true;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // PreInit, PostShutdown
  305. //-----------------------------------------------------------------------------
  306. bool CShaderAPITestApp::PreInit( )
  307. {
  308. if ( !BaseClass::PreInit() )
  309. return false;
  310. if (!g_pFullFileSystem || !g_pShaderDeviceMgr )
  311. return false;
  312. // Add paths...
  313. if ( !SetupSearchPaths() )
  314. return false;
  315. const char *pArg;
  316. int iWidth = 1024;
  317. int iHeight = 768;
  318. bool bWindowed = (CommandLine()->CheckParm( "-fullscreen" ) == NULL);
  319. if (CommandLine()->CheckParm( "-width", &pArg ))
  320. {
  321. iWidth = atoi( pArg );
  322. }
  323. if (CommandLine()->CheckParm( "-height", &pArg ))
  324. {
  325. iHeight = atoi( pArg );
  326. }
  327. if (!CreateAppWindow( "Press a Key To Continue", bWindowed, iWidth, iHeight ))
  328. return false;
  329. return true;
  330. }
  331. void CShaderAPITestApp::PostShutdown( )
  332. {
  333. BaseClass::PostShutdown();
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Waits for a keypress
  337. //-----------------------------------------------------------------------------
  338. bool CShaderAPITestApp::WaitForKeypress()
  339. {
  340. MSG msg = {0};
  341. while( WM_QUIT != msg.message )
  342. {
  343. if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  344. {
  345. TranslateMessage( &msg );
  346. DispatchMessage( &msg );
  347. }
  348. if ( msg.message == WM_KEYDOWN )
  349. return true;
  350. }
  351. return false;
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Displays adapter information
  355. //-----------------------------------------------------------------------------
  356. void CShaderAPITestApp::DisplayAdapterInfo()
  357. {
  358. int nAdapterCount = g_pShaderDeviceMgr->GetAdapterCount();
  359. for ( int i = 0; i < nAdapterCount; ++i )
  360. {
  361. MaterialAdapterInfo_t info;
  362. g_pShaderDeviceMgr->GetAdapterInfo( i, info );
  363. Msg( "Adapter %d\n", i );
  364. Msg( "\tName: %s\n\tVendor: 0x%X\n\tDevice: 0x%X\n\tSubSystem: 0x%X\n\tRevision: 0x%X\n\tRecommended DX Level: %d\n\tMax DX Level: %d\n",
  365. info.m_pDriverName, info.m_VendorID, info.m_DeviceID, info.m_SubSysID, info.m_Revision, info.m_nDXSupportLevel, info.m_nMaxDXSupportLevel );
  366. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  367. KeyValues *pConfiguration = new KeyValues( "Config" );
  368. g_pShaderDeviceMgr->GetRecommendedConfigurationInfo( i, info.m_nDXSupportLevel, pConfiguration );
  369. pConfiguration->RecursiveSaveToFile( buf, 1 );
  370. Msg( "\tConfiguration:\n%s", ( const char * )buf.Base() );
  371. Msg( "\n" );
  372. int nModeCount = g_pShaderDeviceMgr->GetModeCount( i );
  373. Msg( "\tMode Count : %d\n", nModeCount );
  374. for ( int j = 0; j < nModeCount; ++j )
  375. {
  376. ShaderDisplayMode_t mode;
  377. g_pShaderDeviceMgr->GetModeInfo( &mode, i, j );
  378. Msg( "\t\tH: %5d W: %5d Format: %3d Refresh %3d/%3d\n",
  379. mode.m_nWidth, mode.m_nHeight, mode.m_Format, mode.m_nRefreshRateNumerator, mode.m_nRefreshRateDenominator );
  380. }
  381. }
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Sets the video mode
  385. //-----------------------------------------------------------------------------
  386. bool CShaderAPITestApp::SetMode()
  387. {
  388. int nAdapterCount = g_pShaderDeviceMgr->GetAdapterCount();
  389. int nAdapter = CommandLine()->ParmValue( "-adapter", 0 );
  390. if ( nAdapter >= nAdapterCount )
  391. {
  392. Warning( "Specified too high an adapter number on the command-line (%d/%d)!\n", nAdapter, nAdapterCount );
  393. return false;
  394. }
  395. ShaderDeviceInfo_t mode;
  396. mode.m_DisplayMode.m_nWidth = 1024;
  397. mode.m_DisplayMode.m_nHeight = 768;
  398. mode.m_DisplayMode.m_Format = IMAGE_FORMAT_BGRA8888;
  399. mode.m_DisplayMode.m_nRefreshRateNumerator = 60;
  400. mode.m_DisplayMode.m_nRefreshRateDenominator = 1;
  401. mode.m_bWindowed = true;
  402. mode.m_nBackBufferCount = 1;
  403. CreateInterfaceFn shaderFactory = g_pShaderDeviceMgr->SetMode( m_HWnd, nAdapter, mode );
  404. if ( !shaderFactory )
  405. {
  406. Warning( "Unable to set mode!\n" );
  407. return false;
  408. }
  409. m_pShaderAPI = (IShaderAPI*)shaderFactory( SHADERAPI_INTERFACE_VERSION, NULL );
  410. m_pShaderDevice = (IShaderDevice*)shaderFactory( SHADER_DEVICE_INTERFACE_VERSION, NULL );
  411. if ( !m_pShaderAPI || !m_pShaderDevice )
  412. {
  413. Warning( "Unable to get IShaderAPI or IShaderDevice interface!\n" );
  414. return false;
  415. }
  416. return true;
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Creates really simple vertex + index buffers
  420. //-----------------------------------------------------------------------------
  421. void CShaderAPITestApp::CreateSimpleBuffers( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered )
  422. {
  423. VertexFormat_t fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR;
  424. if ( IsDynamicBufferType( nVBType ) )
  425. {
  426. m_pVertexBuffer = m_pShaderDevice->CreateVertexBuffer(
  427. nVBType, VERTEX_FORMAT_UNKNOWN, 1024, "test" );
  428. }
  429. else
  430. {
  431. m_pVertexBuffer = m_pShaderDevice->CreateVertexBuffer(
  432. nVBType, fmt, 4, "test" );
  433. }
  434. static unsigned char s_pColors[4][4] =
  435. {
  436. { 255, 0, 0, 255 },
  437. { 0, 255, 0, 255 },
  438. { 0, 0, 255, 255 },
  439. { 255, 255, 255, 255 },
  440. };
  441. static int nCount = 0;
  442. CVertexBuilder vb( m_pVertexBuffer, fmt );
  443. vb.Lock( 4 );
  444. vb.Position3f( -1.0f, -1.0f, 0.5f );
  445. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  446. vb.Color4ubv( s_pColors[nCount++ % 4] );
  447. vb.AdvanceVertex();
  448. vb.Position3f( 1.0f, -1.0f, 0.5f );
  449. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  450. vb.Color4ubv( s_pColors[nCount++ % 4] );
  451. vb.AdvanceVertex();
  452. vb.Position3f( 1.0f, 1.0f, 0.5f );
  453. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  454. vb.Color4ubv( s_pColors[nCount++ % 4] );
  455. vb.AdvanceVertex();
  456. vb.Position3f( -1.0f, 1.0f, 0.5f );
  457. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  458. vb.Color4ubv( s_pColors[nCount++ % 4] );
  459. vb.AdvanceVertex();
  460. vb.SpewData( );
  461. vb.Unlock( );
  462. ++nCount;
  463. if ( IsDynamicBufferType( nIBType ) )
  464. {
  465. m_pIndexBuffer = m_pShaderDevice->CreateIndexBuffer( nIBType, MATERIAL_INDEX_FORMAT_UNKNOWN, 64, "test" );
  466. }
  467. else
  468. {
  469. m_pIndexBuffer = m_pShaderDevice->CreateIndexBuffer( nIBType, MATERIAL_INDEX_FORMAT_16BIT, 6, "test" );
  470. }
  471. CIndexBuilder ib( m_pIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT );
  472. ib.Lock( 6, 0 );
  473. ib.FastIndex( 0 );
  474. ib.FastIndex( 2 );
  475. ib.FastIndex( 1 );
  476. ib.FastIndex( 0 );
  477. ib.FastIndex( 3 );
  478. ib.FastIndex( 2 );
  479. ib.SpewData();
  480. ib.Unlock( );
  481. m_pShaderAPI->BindVertexBuffer( 0, m_pVertexBuffer, vb.Offset(), 0, vb.TotalVertexCount(), fmt );
  482. m_pShaderAPI->BindIndexBuffer( m_pIndexBuffer, ib.Offset() );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Destroys the buffers
  486. //-----------------------------------------------------------------------------
  487. void CShaderAPITestApp::DestroyBuffers()
  488. {
  489. if ( m_pVertexBuffer )
  490. {
  491. m_pShaderDevice->DestroyVertexBuffer( m_pVertexBuffer );
  492. m_pVertexBuffer = NULL;
  493. }
  494. if ( m_pIndexBuffer )
  495. {
  496. m_pShaderDevice->DestroyIndexBuffer( m_pIndexBuffer );
  497. m_pIndexBuffer = NULL;
  498. }
  499. }
  500. //-----------------------------------------------------------------------------
  501. // shader programs
  502. //-----------------------------------------------------------------------------
  503. static const char s_pSimpleVertexShader[] =
  504. "struct VS_INPUT "
  505. "{ "
  506. " float3 vPos : POSITION0; "
  507. " float4 vColor : COLOR0; "
  508. "}; "
  509. " "
  510. "struct VS_OUTPUT "
  511. "{ "
  512. " float4 projPos : POSITION0; "
  513. " float4 vertexColor : COLOR0; "
  514. "}; "
  515. " "
  516. "VS_OUTPUT main( const VS_INPUT v ) "
  517. "{ "
  518. " VS_OUTPUT o = ( VS_OUTPUT )0; "
  519. " "
  520. " o.projPos.xyz = v.vPos; "
  521. " o.projPos.w = 1.0f; "
  522. " o.vertexColor = v.vColor; "
  523. " return o; "
  524. "} "
  525. "";
  526. static const char s_pSimplePixelShader[] =
  527. "struct PS_INPUT "
  528. "{ "
  529. " float4 projPos : POSITION0; "
  530. " float4 vColor : COLOR0; "
  531. "}; "
  532. " "
  533. "float4 main( const PS_INPUT i ) : COLOR "
  534. "{ "
  535. " return i.vColor; "
  536. "} "
  537. "";
  538. //-----------------------------------------------------------------------------
  539. // Create, destroy shaders
  540. //-----------------------------------------------------------------------------
  541. void CShaderAPITestApp::CreateShaders( const char *pVShader, int nVBufLen, const char *pGShader, int nGBufLen, const char *pPShader, int nPBufLen )
  542. {
  543. const char *pVertexShaderVersion = g_pMaterialSystemHardwareConfig->GetDXSupportLevel() == 100 ? "vs_4_0" : "vs_2_0";
  544. const char *pPixelShaderVersion = g_pMaterialSystemHardwareConfig->GetDXSupportLevel() == 100 ? "ps_4_0" : "ps_2_0";
  545. // Compile shaders
  546. m_hVertexShader = m_pShaderDevice->CreateVertexShader( pVShader, nVBufLen, pVertexShaderVersion );
  547. Assert( m_hVertexShader != VERTEX_SHADER_HANDLE_INVALID );
  548. m_hGeometryShader = GEOMETRY_SHADER_HANDLE_INVALID;
  549. if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 100 )
  550. {
  551. // m_hGeometryShader = m_pShaderDevice->CreateGeometryShader( pGShader, nGBufLen, "gs_4_0" );
  552. // Assert( m_hGeometryShader != GEOMETRY_SHADER_HANDLE_INVALID );
  553. }
  554. m_hPixelShader = m_pShaderDevice->CreatePixelShader( pPShader, nPBufLen, pPixelShaderVersion );
  555. Assert( m_hPixelShader != PIXEL_SHADER_HANDLE_INVALID );
  556. m_pShaderAPI->BindVertexShader( m_hVertexShader );
  557. m_pShaderAPI->BindGeometryShader( m_hGeometryShader );
  558. m_pShaderAPI->BindPixelShader( m_hPixelShader );
  559. }
  560. void CShaderAPITestApp::DestroyShaders()
  561. {
  562. m_pShaderDevice->DestroyVertexShader( m_hVertexShader );
  563. m_pShaderDevice->DestroyGeometryShader( m_hGeometryShader );
  564. m_pShaderDevice->DestroyPixelShader( m_hPixelShader );
  565. m_hVertexShader = VERTEX_SHADER_HANDLE_INVALID;
  566. m_hGeometryShader = GEOMETRY_SHADER_HANDLE_INVALID;
  567. m_hPixelShader = PIXEL_SHADER_HANDLE_INVALID;
  568. }
  569. //-----------------------------------------------------------------------------
  570. // DrawQuad
  571. //-----------------------------------------------------------------------------
  572. void CShaderAPITestApp::TestColoredQuad( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered )
  573. {
  574. // clear (so that we can make sure that we aren't getting results from the previous quad)
  575. m_pShaderAPI->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) );
  576. m_pShaderAPI->ClearBuffers( true, false, false, -1, -1 );
  577. CreateSimpleBuffers( nVBType, nIBType, bBuffered );
  578. // Draw a quad!
  579. CreateShaders( s_pSimpleVertexShader, sizeof(s_pSimpleVertexShader),
  580. NULL, 0, s_pSimplePixelShader, sizeof(s_pSimplePixelShader) );
  581. m_pShaderAPI->Draw( MATERIAL_TRIANGLES, 0, 6 );
  582. m_pShaderDevice->Present();
  583. DestroyShaders();
  584. DestroyBuffers();
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Tests dynamic buffers
  588. //-----------------------------------------------------------------------------
  589. void CShaderAPITestApp::TestDynamicBuffers()
  590. {
  591. m_pVertexBuffer = m_pShaderDevice->CreateVertexBuffer(
  592. SHADER_BUFFER_TYPE_DYNAMIC, VERTEX_FORMAT_UNKNOWN, 0x100, "test" );
  593. m_pIndexBuffer = m_pShaderDevice->CreateIndexBuffer(
  594. SHADER_BUFFER_TYPE_DYNAMIC, MATERIAL_INDEX_FORMAT_UNKNOWN, 30, "test" );
  595. CreateShaders( s_pSimpleVertexShader, sizeof(s_pSimpleVertexShader),
  596. NULL, 0, s_pSimplePixelShader, sizeof(s_pSimplePixelShader) );
  597. // clear (so that we can make sure that we aren't getting results from the previous quad)
  598. m_pShaderAPI->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) );
  599. m_pShaderAPI->ClearBuffers( true, false, false, -1, -1 );
  600. static unsigned char s_pColors[4][4] =
  601. {
  602. { 255, 0, 0, 255 },
  603. { 0, 255, 0, 255 },
  604. { 0, 0, 255, 255 },
  605. { 255, 255, 255, 255 },
  606. };
  607. static int nCount = 0;
  608. VertexFormat_t fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR;
  609. const int nLoopCount = 8;
  610. float flWidth = 2.0f / nLoopCount;
  611. for ( int i = 0; i < nLoopCount; ++i )
  612. {
  613. CVertexBuilder vb( m_pVertexBuffer, fmt );
  614. vb.Lock( 4 );
  615. vb.Position3f( -1.0f + i * flWidth, -1.0f, 0.5f );
  616. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  617. vb.Color4ubv( s_pColors[nCount++ % 4] );
  618. vb.AdvanceVertex();
  619. vb.Position3f( -1.0f + i * flWidth + flWidth, -1.0f, 0.5f );
  620. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  621. vb.Color4ubv( s_pColors[nCount++ % 4] );
  622. vb.AdvanceVertex();
  623. vb.Position3f( -1.0f + i * flWidth + flWidth, 1.0f, 0.5f );
  624. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  625. vb.Color4ubv( s_pColors[nCount++ % 4] );
  626. vb.AdvanceVertex();
  627. vb.Position3f( -1.0f + i * flWidth, 1.0f, 0.5f );
  628. vb.Normal3f( 0.0f, 0.0f, 1.0f );
  629. vb.Color4ubv( s_pColors[nCount++ % 4] );
  630. vb.AdvanceVertex();
  631. vb.SpewData();
  632. vb.Unlock( );
  633. ++nCount;
  634. CIndexBuilder ib( m_pIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT );
  635. ib.Lock( 6, vb.GetFirstVertex() );
  636. ib.FastIndex( 0 );
  637. ib.FastIndex( 2 );
  638. ib.FastIndex( 1 );
  639. ib.FastIndex( 0 );
  640. ib.FastIndex( 3 );
  641. ib.FastIndex( 2 );
  642. ib.SpewData();
  643. ib.Unlock( );
  644. m_pShaderAPI->BindVertexBuffer( 0, m_pVertexBuffer, vb.Offset(), vb.GetFirstVertex(), vb.TotalVertexCount(), fmt );
  645. m_pShaderAPI->BindIndexBuffer( m_pIndexBuffer, ib.Offset() );
  646. m_pShaderAPI->Draw( MATERIAL_TRIANGLES, ib.GetFirstIndex(), ib.TotalIndexCount() );
  647. }
  648. m_pShaderDevice->Present();
  649. ++nCount;
  650. DestroyShaders();
  651. DestroyBuffers();
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Create dynamic combos
  655. //-----------------------------------------------------------------------------
  656. static uint32 NextULONG( uint8 * &pData )
  657. {
  658. // handle unaligned read
  659. uint32 nRet;
  660. memcpy( &nRet, pData, sizeof( nRet ) );
  661. pData += sizeof( nRet );
  662. return nRet;
  663. }
  664. bool CShaderAPITestApp::CreateDynamicCombos_Ver5( uint8 *pComboBuffer, bool bVertexShader )
  665. {
  666. uint8 *pCompressedShaders = pComboBuffer;
  667. uint8 *pUnpackBuffer = new uint8[MAX_SHADER_UNPACKED_BLOCK_SIZE];
  668. // now, loop through all blocks
  669. bool bOK = true;
  670. while ( bOK )
  671. {
  672. uint32 nBlockSize = NextULONG( pCompressedShaders );
  673. if ( nBlockSize == 0xffffffff )
  674. {
  675. // any more blocks?
  676. break;
  677. }
  678. switch( nBlockSize & 0xc0000000 )
  679. {
  680. case 0: // bzip2
  681. {
  682. // uncompress
  683. uint32 nOutsize = MAX_SHADER_UNPACKED_BLOCK_SIZE;
  684. int nRslt = BZ2_bzBuffToBuffDecompress(
  685. reinterpret_cast<char *>( pUnpackBuffer ),
  686. &nOutsize,
  687. reinterpret_cast<char *>( pCompressedShaders ),
  688. nBlockSize, 1, 0 );
  689. if ( nRslt < 0 )
  690. {
  691. // errors are negative for bzip
  692. Assert( 0 );
  693. Warning( "BZIP Error (%d) decompressing shader", nRslt );
  694. bOK = false;
  695. }
  696. pCompressedShaders += nBlockSize;
  697. nBlockSize = nOutsize; // how much data there is
  698. }
  699. break;
  700. case 0x80000000: // uncompressed
  701. {
  702. // not compressed, as is
  703. nBlockSize &= 0x3fffffff;
  704. memcpy( pUnpackBuffer, pCompressedShaders, nBlockSize );
  705. pCompressedShaders += nBlockSize;
  706. }
  707. break;
  708. case 0x40000000: // lzma compressed
  709. {
  710. nBlockSize &= 0x3fffffff;
  711. size_t nOutsize = CLZMA::Uncompress(
  712. reinterpret_cast<uint8 *>( pCompressedShaders ),
  713. pUnpackBuffer );
  714. pCompressedShaders += nBlockSize;
  715. nBlockSize = nOutsize; // how much data there is
  716. }
  717. break;
  718. default:
  719. {
  720. Assert( 0 );
  721. Error(" unrecognized shader compression type = file corrupt?");
  722. bOK = false;
  723. }
  724. }
  725. uint8 *pReadPtr = pUnpackBuffer;
  726. while ( pReadPtr < pUnpackBuffer+nBlockSize )
  727. {
  728. uint32 nCombo_ID = NextULONG( pReadPtr );
  729. (void)nCombo_ID; // Suppress local variable is initialized but not referenced warning
  730. uint32 nShaderSize = NextULONG( pReadPtr );
  731. CUtlBuffer buf( pReadPtr, nShaderSize );
  732. if ( bVertexShader )
  733. {
  734. m_pShaderDevice->CreateVertexShader( buf, "vs_2_0" );
  735. }
  736. else
  737. {
  738. m_pShaderDevice->CreatePixelShader( buf, "ps_2_b" );
  739. }
  740. pReadPtr += nShaderSize;
  741. }
  742. }
  743. delete[] pUnpackBuffer;
  744. return bOK;
  745. }
  746. //-----------------------------------------------------------------------------
  747. // Load shader
  748. //-----------------------------------------------------------------------------
  749. void CShaderAPITestApp::LoadShaderFile( const char *pName, bool bVertexShader )
  750. {
  751. // next, try the fxc dir
  752. char pFileName[MAX_PATH];
  753. Q_snprintf( pFileName, MAX_PATH, "..\\hl2\\shaders\\fxc\\%s.vcs", pName );
  754. FileHandle_t hFile = g_pFullFileSystem->Open( pFileName, "rb", "EXECUTABLE_PATH" );
  755. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  756. {
  757. Warning( "Couldn't load %s shader %s\n", bVertexShader ? "vertex" : "pixel", pName );
  758. return;
  759. }
  760. ShaderHeader_t header;
  761. g_pFullFileSystem->Read( &header, sizeof( ShaderHeader_t ), hFile );
  762. // cache the dictionary
  763. int nComboSize = header.m_nNumStaticCombos * sizeof( StaticComboRecord_t );
  764. StaticComboRecord_t *pRecords = (StaticComboRecord_t *)malloc( nComboSize );
  765. g_pFullFileSystem->Read( pRecords, nComboSize, hFile );
  766. for ( unsigned int i = 0; i < header.m_nNumStaticCombos - 1; ++i )
  767. {
  768. int nStartingOffset = pRecords[i].m_nFileOffset;
  769. int nEndingOffset = pRecords[i+1].m_nFileOffset;
  770. int nShaderSize = nEndingOffset - nStartingOffset;
  771. uint8 *pBuf = (uint8*)malloc( nShaderSize );
  772. g_pFullFileSystem->Seek( hFile, nStartingOffset, FILESYSTEM_SEEK_HEAD );
  773. g_pFullFileSystem->Read( pBuf, nShaderSize, hFile );
  774. CreateDynamicCombos_Ver5( pBuf, bVertexShader );
  775. free( pBuf );
  776. }
  777. free( pRecords );
  778. g_pFullFileSystem->Close( hFile );
  779. }
  780. //-----------------------------------------------------------------------------
  781. // main application
  782. //-----------------------------------------------------------------------------
  783. int CShaderAPITestApp::Main()
  784. {
  785. DisplayAdapterInfo();
  786. if ( !SetMode() )
  787. return 0;
  788. // Test buffer clearing
  789. m_pShaderAPI->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) );
  790. m_pShaderAPI->ClearBuffers( true, false, false, -1, -1 );
  791. m_pShaderDevice->Present();
  792. SetWindowText( m_HWnd, "ClearBuffers test results . . hit a key" );
  793. if ( !WaitForKeypress() )
  794. return 1;
  795. // Test viewport
  796. int nMaxViewports = g_pMaterialSystemHardwareConfig->MaxViewports();
  797. ShaderViewport_t* pViewports = ( ShaderViewport_t* )_alloca( nMaxViewports * sizeof(ShaderViewport_t) );
  798. for ( int i = 0; i < nMaxViewports; ++i )
  799. {
  800. int x = RandomInt( 0, 100 );
  801. int y = RandomInt( 0, 100 );
  802. int w = RandomInt( 100, 200 );
  803. int h = RandomInt( 100, 200 );
  804. pViewports[i].Init( x, y, w, h );
  805. m_pShaderAPI->SetViewports( i+1, pViewports );
  806. }
  807. SetWindowText( m_HWnd, "SetViewports test results . . hit a key" );
  808. if ( !WaitForKeypress() )
  809. return 1;
  810. // Sets up a full-screen viewport
  811. int w, h;
  812. m_pShaderDevice->GetWindowSize( w, h );
  813. ShaderViewport_t viewport;
  814. viewport.Init( 0, 0, w, h );
  815. m_pShaderAPI->SetViewports( 1, &viewport );
  816. // Test drawing a full-screen quad with interpolated vertex colors for every combo of static/dynamic VB, static dynamic IB, buffered/non-buffered.
  817. char buf[1024];
  818. for ( int nVBType = 0; nVBType < SHADER_BUFFER_TYPE_COUNT; ++nVBType )
  819. {
  820. // FIXME: Remove
  821. if ( nVBType > SHADER_BUFFER_TYPE_DYNAMIC )
  822. continue;
  823. for( int nIBType = 0; nIBType < SHADER_BUFFER_TYPE_COUNT; ++nIBType )
  824. {
  825. // FIXME: Remove
  826. if ( nIBType > SHADER_BUFFER_TYPE_DYNAMIC )
  827. continue;
  828. // MESHFIXME: make buffered vertex buffers/index buffers work.
  829. int nBuffered = 0;
  830. // for( nBuffered = 0; nBuffered < 2; nBuffered++ )
  831. {
  832. TestColoredQuad( (ShaderBufferType_t)nVBType, (ShaderBufferType_t)nIBType, nBuffered != 0 );
  833. sprintf( buf, "TestColoredQuad results VB: %d IB: %d Buffered: %d HIT A KEY!",
  834. nVBType, nIBType, nBuffered != 0 );
  835. SetWindowText( m_HWnd, buf );
  836. if ( !WaitForKeypress() )
  837. return 1;
  838. }
  839. }
  840. }
  841. SetWindowText( m_HWnd, "Dynamic Buffer Test: HIT A KEY!" );
  842. TestDynamicBuffers();
  843. if ( !WaitForKeypress() )
  844. return 1;
  845. g_pMaterialSystemHardwareConfig->OverrideStreamOffsetSupport( true, false );
  846. SetWindowText( m_HWnd, "Dynamic Buffer Test (no stream offset): HIT A KEY!" );
  847. TestDynamicBuffers();
  848. if ( !WaitForKeypress() )
  849. return 1;
  850. g_pMaterialSystemHardwareConfig->OverrideStreamOffsetSupport( false, false );
  851. return 1;
  852. }