@@ -39,6 +39,7 @@ static void drawFramerateBar(void);
3939#include < windows.h>
4040#include < io.h>
4141#include < time.h>
42+ #include < d3dx8core.h>
4243
4344// USER INCLUDES //////////////////////////////////////////////////////////////
4445#include " Common/FramePacer.h"
@@ -109,6 +110,8 @@ static void drawFramerateBar(void);
109110
110111#include " WinMain.h"
111112
113+ #include < rts/profile.h>
114+
112115
113116// DEFINE AND ENUMS ///////////////////////////////////////////////////////////
114117
@@ -411,6 +414,7 @@ W3DDisplay::W3DDisplay()
411414// =============================================================================
412415W3DDisplay::~W3DDisplay ()
413416{
417+ ResetTracyCaptureImage ();
414418
415419 // get rid of the debug display
416420 delete m_debugDisplay;
@@ -541,6 +545,8 @@ void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate
541545// =============================================================================
542546Bool W3DDisplay::setDisplayMode ( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed )
543547{
548+ ResetTracyCaptureImage ();
549+
544550 if (WW3D_ERROR_OK == WW3D::Set_Device_Resolution (xres,yres,bitdepth,windowed,true ))
545551 {
546552 Render2DClass::Set_Screen_Resolution (RectClass (0 , 0 , xres, yres));
@@ -1650,6 +1656,202 @@ void W3DDisplay::step()
16501656
16511657// DECLARE_PERF_TIMER(BigAssRenderLoop)
16521658
1659+ #ifdef TRACY_ENABLE
1660+ bool W3DDisplay::InitTracyCaptureImage ()
1661+ {
1662+ // allocate render target
1663+ m_tracyRenderTarget = DX8Wrapper::Create_Render_Target (TRACY_FRAMEIMAGE_SIZE , TRACY_FRAMEIMAGE_SIZE , WW3D_FORMAT_A8R8G8B8 );
1664+ if (!m_tracyRenderTarget)
1665+ return false ;
1666+
1667+ // allocate surface class
1668+ const Real aspectRatio = static_cast <float >(getHeight ()) / static_cast <float >(getWidth ());
1669+ unsigned int tracyImageHeight = MIN (
1670+ static_cast <unsigned int >(WWMath::Round (static_cast <float >(TRACY_FRAMEIMAGE_SIZE ) * aspectRatio)),
1671+ TRACY_FRAMEIMAGE_SIZE );
1672+ m_tracySurfaceClass = NEW_REF (SurfaceClass, (TRACY_FRAMEIMAGE_SIZE , tracyImageHeight, WW3D_FORMAT_A8R8G8B8 ));
1673+ if (!m_tracySurfaceClass)
1674+ return false ;
1675+
1676+ // allocate intermediate texture
1677+ SurfaceClass *backBuffer = DX8Wrapper::_Get_DX8_Back_Buffer ();
1678+ if (!backBuffer)
1679+ return false ;
1680+
1681+ IDirect3DSurface8 *backBufferSurface = backBuffer->Peek_D3D_Surface ();
1682+ D3DSURFACE_DESC backBufferSurfaceDesc;
1683+ HRESULT hr = backBufferSurface->GetDesc (&backBufferSurfaceDesc);
1684+ if (FAILED (hr))
1685+ return false ;
1686+
1687+ IDirect3DDevice8 *device = DX8Wrapper::_Get_D3D_Device8 ();
1688+ hr = device->CreateTexture (
1689+ backBufferSurfaceDesc.Width ,
1690+ backBufferSurfaceDesc.Height ,
1691+ 1 ,
1692+ D3DUSAGE_RENDERTARGET ,
1693+ backBufferSurfaceDesc.Format ,
1694+ D3DPOOL_DEFAULT ,
1695+ &m_tracyIntermediateTexture);
1696+ if (FAILED (hr))
1697+ return false ;
1698+
1699+ // swizzle shader
1700+ // TheSuperHackers @todo In DX9 with ps2.0 this shader will be much simpler
1701+ ID3DXBuffer *compiledShader = nullptr ;
1702+ static const char *shader =
1703+ " ps.1.4\n "
1704+ " texld r0, t0\n "
1705+ " mov r1.a, r0.r\n "
1706+ " mov r2.a, r0.g\n "
1707+ " mov r3.a, r0.b\n "
1708+ " mul r0.rgb, r3.a, c0\n "
1709+ " mad r0.rgb, r2.a, c1, r0\n "
1710+ " mad r0.rgb, r1.a, c2, r0\n " ;
1711+ hr = D3DXAssembleShader (shader, strlen (shader), 0 , nullptr , &compiledShader, nullptr );
1712+ if (FAILED (hr))
1713+ return false ;
1714+
1715+ hr = DX8Wrapper::_Get_D3D_Device8 ()->CreatePixelShader ((DWORD *)compiledShader->GetBufferPointer (), &m_tracySwizzleShader);
1716+ compiledShader->Release ();
1717+ if (FAILED (hr))
1718+ return false ;
1719+
1720+ return true ;
1721+ }
1722+
1723+ void W3DDisplay::ResetTracyCaptureImage ()
1724+ {
1725+ if (m_tracySurfaceClass)
1726+ {
1727+ REF_PTR_RELEASE (m_tracySurfaceClass);
1728+ }
1729+ if (m_tracyIntermediateTexture)
1730+ {
1731+ m_tracyIntermediateTexture->Release ();
1732+ m_tracyIntermediateTexture = nullptr ;
1733+ }
1734+ if (m_tracyRenderTarget)
1735+ {
1736+ REF_PTR_RELEASE (m_tracyRenderTarget);
1737+ }
1738+ if (m_tracySwizzleShader)
1739+ {
1740+ DX8Wrapper::_Get_D3D_Device8 ()->DeletePixelShader (m_tracySwizzleShader);
1741+ m_tracySwizzleShader = 0 ;
1742+ }
1743+ }
1744+
1745+ void W3DDisplay::TracyCaptureImage ()
1746+ {
1747+ if (!TracyIsConnected || !m_tracyFrameCapturing)
1748+ return ;
1749+
1750+ if (!m_tracyRenderTarget)
1751+ {
1752+ if (!InitTracyCaptureImage ()) {
1753+ DEBUG_LOG (" Tracy frame capturing failed to initialize and will be disabled." );
1754+ m_tracyFrameCapturing = false ;
1755+ ResetTracyCaptureImage ();
1756+ return ;
1757+ }
1758+ }
1759+
1760+ // copy the backbuffer to an intermediate texture on the GPU
1761+ // TheSuperHackers @todo In DX9 it should be possible to sample the backbuffer directly and simplify this
1762+ SurfaceClass *backBuffer = DX8Wrapper::_Get_DX8_Back_Buffer ();
1763+ IDirect3DSurface8 *backBufferSurface = backBuffer->Peek_D3D_Surface ();
1764+ D3DSURFACE_DESC backBufferSurfaceDesc;
1765+ backBufferSurface->GetDesc (&backBufferSurfaceDesc);
1766+
1767+ IDirect3DSurface8 *tracyBackbufferTextureSurface;
1768+ m_tracyIntermediateTexture->GetSurfaceLevel (0 , &tracyBackbufferTextureSurface);
1769+ DX8Wrapper::_Copy_DX8_Rects (backBufferSurface, nullptr , 0 ,
1770+ tracyBackbufferTextureSurface, nullptr );
1771+ tracyBackbufferTextureSurface->Release ();
1772+ tracyBackbufferTextureSurface = nullptr ;
1773+
1774+ backBufferSurface->Release ();
1775+ backBufferSurface = nullptr ;
1776+ REF_PTR_RELEASE (backBuffer);
1777+
1778+ // set render target to a small surface
1779+ IDirect3DSurface8 *smallRenderTargetSurface = m_tracyRenderTarget->Get_D3D_Surface_Level ();
1780+ DX8Wrapper::Set_Render_Target (smallRenderTargetSurface, false );
1781+
1782+ // set viewport
1783+ IDirect3DDevice8 *device = DX8Wrapper::_Get_D3D_Device8 ();
1784+ D3DVIEWPORT8 restoreViewport;
1785+ device->GetViewport (&restoreViewport);
1786+
1787+ SurfaceClass::SurfaceDescription smallRenderDesc;
1788+ m_tracySurfaceClass->Get_Description (smallRenderDesc);
1789+
1790+ D3DVIEWPORT8 viewport;
1791+ viewport.X = 0 ;
1792+ viewport.Y = 0 ;
1793+ viewport.Width = TRACY_FRAMEIMAGE_SIZE ;
1794+ viewport.Height = smallRenderDesc.Height ;
1795+ viewport.MinZ = 0 .0f ;
1796+ viewport.MaxZ = 1 .0f ;
1797+ DX8Wrapper::Set_Viewport (&viewport);
1798+
1799+ // bind shader to convert BGRA to RGBA to match the format that Tracy expects
1800+ DX8Wrapper::Set_Pixel_Shader (m_tracySwizzleShader);
1801+ // TheSuperHackers @todo In DX9 with ps2.0 we wont need these pixel shader constants
1802+ static const float kMaskR [4 ] = {1 .0f , 0 .0f , 0 .0f , 0 .0f };
1803+ static const float kMaskG [4 ] = {0 .0f , 1 .0f , 0 .0f , 0 .0f };
1804+ static const float kMaskB [4 ] = {0 .0f , 0 .0f , 1 .0f , 0 .0f };
1805+ device->SetPixelShaderConstant (0 , kMaskR , 1 );
1806+ device->SetPixelShaderConstant (1 , kMaskG , 1 );
1807+ device->SetPixelShaderConstant (2 , kMaskB , 1 );
1808+
1809+ // draw texture scaled-down onto a small surface
1810+ struct QuadVertex
1811+ {
1812+ float x, y, z, rhw;
1813+ DWORD color;
1814+ float u;
1815+ float v;
1816+ } vtx[4 ];
1817+ const float left = -0 .5f ;
1818+ const float top = -0 .5f ;
1819+ const float right = static_cast <float >(TRACY_FRAMEIMAGE_SIZE ) - 0 .5f ;
1820+ const float bottom = static_cast <float >(smallRenderDesc.Height ) - 0 .5f ;
1821+ vtx[0 ] = {right, bottom, 0 .0f , 1 .0f , 0xffffffff , 1 .0f , 1 .0f };
1822+ vtx[1 ] = {right, top, 0 .0f , 1 .0f , 0xffffffff , 1 .0f , 0 .0f };
1823+ vtx[2 ] = {left, bottom, 0 .0f , 1 .0f , 0xffffffff , 0 .0f , 1 .0f };
1824+ vtx[3 ] = {left, top, 0 .0f , 1 .0f , 0xffffffff , 0 .0f , 0 .0f };
1825+ DX8Wrapper::Set_DX8_Texture (0 , m_tracyIntermediateTexture);
1826+ DX8Wrapper::Set_Vertex_Shader (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 );
1827+ device->DrawPrimitiveUP (D3DPT_TRIANGLESTRIP , 2 , vtx, sizeof (QuadVertex));
1828+ DX8Wrapper::Set_Pixel_Shader (0 );
1829+ DX8Wrapper::Set_DX8_Texture (0 , nullptr );
1830+ DX8Wrapper::Set_Viewport (&restoreViewport);
1831+ DX8Wrapper::Set_Render_Target ((IDirect3DSurface8 *) nullptr );
1832+
1833+ // copy the small surface pixels from GPU to CPU
1834+ RECT srcRect = { 0 , 0 , TRACY_FRAMEIMAGE_SIZE , smallRenderDesc.Height };
1835+ POINT dstPoint = { 0 , 0 };
1836+ DX8Wrapper::_Copy_DX8_Rects (
1837+ smallRenderTargetSurface,
1838+ &srcRect,
1839+ 1 ,
1840+ m_tracySurfaceClass->Peek_D3D_Surface (),
1841+ &dstPoint);
1842+ smallRenderTargetSurface->Release ();
1843+
1844+ // send pixels to tracy
1845+ int pitch = 0 ;
1846+ void *bits = m_tracySurfaceClass->Lock (&pitch);
1847+ if (bits)
1848+ {
1849+ FrameImage (bits, TRACY_FRAMEIMAGE_SIZE , smallRenderDesc.Height , 0 , false );
1850+ m_tracySurfaceClass->Unlock ();
1851+ }
1852+ }
1853+ #endif
1854+
16531855// W3DDisplay::draw ===========================================================
16541856/* * Draw the entire W3D Display */
16551857// =============================================================================
@@ -1935,6 +2137,7 @@ void W3DDisplay::draw( void )
19352137 TheGraphDraw->render ();
19362138 TheGraphDraw->clear ();
19372139#endif
2140+ TracyCaptureImage ();
19382141 // render is all done!
19392142 WW3D::End_Render ();
19402143 }
0 commit comments