|
|
//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef IRENDERDEVICE_H
#define IRENDERDEVICE_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/interface.h"
#include "appframework/iappsystem.h"
#include "bitmap/imageformat.h"
#include "tier1/utlbuffer.h"
#include "mathlib/vector4d.h"
#include "bitmap/colorformat.h"
#include "rendersystem/renderstate.h"
#include "resourcesystem/stronghandle.h"
#include "rendersystem/schema/texture.g.h"
#include "rendersystem/schema/renderbuffer.g.h"
#include "rendersystem/schema/renderable.g.h"
#include "tier0/platwindow.h"
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
class KeyValues; struct RenderInputLayoutField_t; class IRenderContext; struct Rect_t;
//-----------------------------------------------------------------------------
// turn this on to get logging
//----------------------------------------------------------------------------
//#define LOG_COMMAND_BUFFER_EXECUTE
//-----------------------------------------------------------------------------
// Adapter info
//-----------------------------------------------------------------------------
enum { RENDER_ADAPTER_NAME_LENGTH = 512 };
struct RenderAdapterInfo_t { char m_pDriverName[RENDER_ADAPTER_NAME_LENGTH]; unsigned int m_VendorID; unsigned int m_DeviceID; unsigned int m_SubSysID; unsigned int m_Revision; int m_nDXSupportLevel; // This is the *preferred* dx support level
int m_nMinDXSupportLevel; int m_nMaxDXSupportLevel; unsigned int m_nDriverVersionHigh; unsigned int m_nDriverVersionLow; };
//-----------------------------------------------------------------------------
// Flags to be used with the CreateDevice call
//-----------------------------------------------------------------------------
enum RenderCreateDeviceFlags_t { RENDER_CREATE_DEVICE_RESIZE_WINDOWS = 0x1, };
//-----------------------------------------------------------------------------
// Describes how to set the mode
//-----------------------------------------------------------------------------
#define RENDER_DISPLAY_MODE_VERSION 1
struct RenderDisplayMode_t { RenderDisplayMode_t() { memset( this, 0, sizeof(RenderDisplayMode_t) ); m_nVersion = RENDER_DISPLAY_MODE_VERSION; }
int m_nVersion; int m_nWidth; // 0 when running windowed means use desktop resolution
int m_nHeight; ImageFormat m_Format; // use ImageFormats (ignored for windowed mode)
int m_nRefreshRateNumerator; // Refresh rate. Use 0 in numerator + denominator for a default setting.
int m_nRefreshRateDenominator; // Refresh rate = numerator / denominator.
};
//-----------------------------------------------------------------------------
// Describes how to set the device
//-----------------------------------------------------------------------------
#define RENDER_DEVICE_INFO_VERSION 1
struct RenderDeviceInfo_t { RenderDeviceInfo_t() { memset( this, 0, sizeof(RenderDeviceInfo_t) ); m_nVersion = RENDER_DEVICE_INFO_VERSION; m_DisplayMode.m_nVersion = RENDER_DISPLAY_MODE_VERSION; }
int m_nVersion; RenderDisplayMode_t m_DisplayMode; int m_nBackBufferCount; // valid values are 1 or 2 [2 results in triple buffering]
RenderMultisampleType_t m_nMultisampleType;
bool m_bFullscreen : 1; bool m_bUseStencil : 1; bool m_bWaitForVSync : 1; // Would we not present until vsync?
bool m_bScaleToOutputResolution : 1;// 360 ONLY: sets up hardware scaling
bool m_bProgressive : 1; // 360 ONLY: interlaced or progressive
bool m_bUsingMultipleWindows : 1; // Forces D3DPresent to use _COPY instead
};
//-----------------------------------------------------------------------------
// Vertex field description
//-----------------------------------------------------------------------------
enum { RENDER_INPUT_LAYOUT_FIELD_SEMANTIC_NAME_SIZE = 32, };
struct RenderInputLayoutField_t { char m_pSemanticName[RENDER_INPUT_LAYOUT_FIELD_SEMANTIC_NAME_SIZE]; int m_nSemanticIndex; ColorFormat_t m_Format; int m_nOffset; int m_nSlot; RenderSlotType_t m_nSlotType; int m_nInstanceStepRate; };
#define DEFINE_PER_VERTEX_FIELD( _slot, _name, _index, _vertexformat, _field ) \
{ _name, _index, ComputeColorFormat( &(((_vertexformat*)0)->_field) ), offsetof( _vertexformat, _field ), _slot, RENDER_SLOT_PER_VERTEX, 0 },
#define DEFINE_PER_INSTANCE_FIELD( _slot, _stepRate, _name, _index, _vertexformat, _field ) \
{ _name, _index, ComputeColorFormat( &(((_vertexformat*)0)->_field) ), offsetof( _vertexformat, _field ), _slot, RENDER_SLOT_PER_INSTANCE, _stepRate },
//-----------------------------------------------------------------------------
// When we switch render target bindings, should we keep the contents?
//-----------------------------------------------------------------------------
enum RenderTargetBindingFlags_t { DISCARD_CONTENTS = 0x00, PRESERVE_COLOR0 = 0x01, // corresponds to Render Target 0
PRESERVE_COLOR1 = 0x02, // corresponds to Render Target 1
PRESERVE_COLOR2 = 0x04, PRESERVE_COLOR3 = 0x08, PRESERVE_DEPTHSTENCIL = 0x10, PRESERVE_CONTENTS = PRESERVE_COLOR0 | PRESERVE_COLOR1 | PRESERVE_COLOR2 | PRESERVE_COLOR3 | PRESERVE_DEPTHSTENCIL,
TILE_VERTICALLY = 0x20, // by default, we tile horizontally (splits are vertical)
};
//-----------------------------------------------------------------------------
// Variations on input layouts
// These are used to support various types of instancing
//-----------------------------------------------------------------------------
enum InputLayoutVariation_t { INPUT_LAYOUT_VARIATION_DEFAULT = 0x00, INPUT_LAYOUT_VARIATION_STREAM1_MAT3X4, INPUT_LAYOUT_VARIATION_STREAM1_MAT4X4,
INPUT_LAYOUT_VARIATION_MAX };
//-----------------------------------------------------------------------------
// Handle to a vertex format
//-----------------------------------------------------------------------------
DECLARE_HANDLE_32BIT( RenderInputLayout_t ); #define RENDER_INPUT_LAYOUT_INVALID ( RenderInputLayout_t::MakeHandle( (uint32)~0 ) )
//-----------------------------------------------------------------------------
// Standard texture handles
//-----------------------------------------------------------------------------
#define RENDER_TEXTURE_DEFAULT_RENDER_TARGET ( (HRenderTexture)-1 )
//-----------------------------------------------------------------------------
// Handle to a render resource
//-----------------------------------------------------------------------------
DECLARE_POINTER_HANDLE( RenderResourceHandle_t ); #define RENDER_RESOURCE_HANDLE_INVALID ( (RenderResourceHandle_t)0 )
//-----------------------------------------------------------------------------
// Handle to a class that describes which render targets are in use
//-----------------------------------------------------------------------------
DECLARE_DERIVED_POINTER_HANDLE( RenderTargetBinding_t, RenderResourceHandle_t ); #define RENDER_TARGET_BINDING_INVALID ( (RenderTargetBinding_t)0 )
#define RENDER_TARGET_BINDING_BACK_BUFFER ( (RenderTargetBinding_t)-1 )
//-----------------------------------------------------------------------------
// Handle to a vertex, pixel, geometry, etc. shader
//-----------------------------------------------------------------------------
DECLARE_DERIVED_POINTER_HANDLE( RenderShaderHandle_t, RenderResourceHandle_t ); #define RENDER_SHADER_HANDLE_INVALID ( (RenderShaderHandle_t)0 )
enum RenderShaderType_t { RENDER_SHADER_TYPE_INVALID = -1, RENDER_PIXEL_SHADER = 0, RENDER_VERTEX_SHADER, RENDER_GEOMETRY_SHADER,
RENDER_SHADER_TYPE_COUNT, };
//-----------------------------------------------------------------------------
// Handle to a vertex buffer/indexbuffer
//-----------------------------------------------------------------------------
DECLARE_DERIVED_POINTER_HANDLE( VertexBufferHandle_t, RenderResourceHandle_t ); DECLARE_DERIVED_POINTER_HANDLE( IndexBufferHandle_t, RenderResourceHandle_t );
#define VERTEX_BUFFER_HANDLE_INVALID ( (VertexBufferHandle_t)0 )
#define INDEX_BUFFER_HANDLE_INVALID ( (IndexBufferHandle_t)0 )
//-----------------------------------------------------------------------------
// constant buffers
//-----------------------------------------------------------------------------
DECLARE_DERIVED_POINTER_HANDLE( ConstantBufferHandle_t, RenderResourceHandle_t ); #define CONSTANT_BUFFER_HANDLE_INVALID ( ( ConstantBufferHandle_t ) 0 )
//-----------------------------------------------------------------------------
// A shader buffer returns a block of memory which must be released when done with it
//-----------------------------------------------------------------------------
abstract_class IRenderShaderBuffer { public: virtual size_t GetSize() const = 0; virtual const void* GetBits() const = 0; virtual void Release() = 0; };
//-----------------------------------------------------------------------------
// Swap chain handle
//-----------------------------------------------------------------------------
DECLARE_POINTER_HANDLE( SwapChainHandle_t ); #define SWAP_CHAIN_HANDLE_INVALID ( (SwapChainHandle_t)0 )
//-----------------------------------------------------------------------------
// Mode change callback
//-----------------------------------------------------------------------------
typedef void (*RenderModeChangeCallbackFunc_t)( void );
//-----------------------------------------------------------------------------
// This is a little wacky. It's super convenient for app systems to be
// able to use the render device in their Init() blocks. This is tricky
// however because we don't have a great way of getting data to the
// devicemgr so it knows how to create the device. Specifically, we need to
// tell it which adapter to use, whether we're going to have resizing windows,
// and what window we're going to have 3D on (this is a dx9 restriction).
// So, we need to be able to run application code right after renderdevice init
// but before any other inits. The other alternative is for the application
// to send information to the render device mgr post connect but pre init.
// The first option is better because it lets the application do arbitrary
// stuff after it can query information about adapters, etc.
//-----------------------------------------------------------------------------
abstract_class IRenderDeviceSetup { public: // This will be called by the render device mgr after it initializes itself
virtual bool CreateRenderDevice() = 0; };
//-----------------------------------------------------------------------------
// Methods related to discovering and selecting devices
//-----------------------------------------------------------------------------
abstract_class IRenderDeviceMgr : public IAppSystem { public: // Gets the number of adapters...
virtual int GetAdapterCount() const = 0;
// Returns info about each adapter
virtual void GetAdapterInfo( int nAdapter, RenderAdapterInfo_t& info ) const = 0;
// Gets recommended congifuration for a particular adapter at a particular dx level
virtual bool GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, KeyValues *pConfiguration ) = 0;
// Returns the number of modes
virtual int GetModeCount( int nAdapter ) const = 0;
// Returns mode information..
virtual void GetModeInfo( RenderDisplayMode_t* pInfo, int nAdapter, int nMode ) const = 0;
// Returns the current mode info for the requested adapter
virtual void GetCurrentModeInfo( RenderDisplayMode_t* pInfo, int nAdapter ) const = 0;
// Use the returned factory to get at an IRenderDevice and an IHardwareConfig
// and any other interfaces we decide to create.
// A returned factory of NULL indicates the device was not created properly.
virtual CreateInterfaceFn CreateDevice( int nAdapter, int nFlags, int nDXLevel = 0 ) = 0;
// Installs a callback to get called
virtual void AddModeChangeCallback( RenderModeChangeCallbackFunc_t func ) = 0; virtual void RemoveModeChangeCallback( RenderModeChangeCallbackFunc_t func ) = 0;
virtual bool GetRecommendedVideoConfig( int nAdapter, KeyValues *pConfiguration ) = 0;
// Destroys the device
virtual void DestroyDevice() = 0;
// Method to allow callbacks to set up the device during init
// See big comment above IRenderDeviceSetup for why this is necessary
virtual void InstallRenderDeviceSetup( IRenderDeviceSetup *pSetup ) = 0; };
//-----------------------------------------------------------------------------
// Data for vertex/index buffer creation
//-----------------------------------------------------------------------------
struct BufferDesc_t { int m_nElementCount; // Number of vertices/indices
int m_nElementSizeInBytes; // Size of a single vertex/index
const char * m_pDebugName; // Used to debug buffers
const char * m_pBudgetGroupName; };
//-----------------------------------------------------------------------------
// Base class for abstract dependency class obtained and managed by the render device. These MUST
// be gotten from the device in order to be used in submits. Application code only needs to treat
// these as pointers/handles
//-----------------------------------------------------------------------------
class CDependencyDescriptor;
enum RenderSystemAssetFileLoadMode_t // controls behavior when rendersystem assets are created from files
{ LOADMODE_IMMEDIATE, // asset is created and loaded from disk immediately
LOADMODE_ASYNCHRONOUS, // asset will start loading asynchronously
LOADMODE_STREAMED, // asset will be asynchronously loaded when referenced.
};
//-----------------------------------------------------------------------------
// Methods related to control of the device
//-----------------------------------------------------------------------------
abstract_class IRenderDevice { public: // Creates a 'swap chain' which represents a back buffer and a window.
// When present happens, you must pass it a swap chain handle.
virtual SwapChainHandle_t CreateSwapChain( PlatWindow_t hWnd, const RenderDeviceInfo_t &mode ) = 0; virtual void DestroySwapChain( SwapChainHandle_t hSwapChain ) = 0;
virtual void UpdateSwapChain( SwapChainHandle_t hSwapChain, const RenderDeviceInfo_t &mode ) = 0; virtual const RenderDeviceInfo_t &GetSwapChainInfo( SwapChainHandle_t hSwapChain ) const = 0;
// Returns the window associated with a swap chain
virtual PlatWindow_t GetSwapChainWindow( SwapChainHandle_t hSwapChain ) const = 0;
// Releases/reloads resources when other apps want some memory
virtual void ReleaseResources() = 0; virtual void ReacquireResources() = 0;
// returns the backbuffer format and dimensions
virtual ImageFormat GetBackBufferFormat( SwapChainHandle_t hSwapChain ) const = 0; virtual void GetBackBufferDimensions( SwapChainHandle_t hSwapChain, int *pWidth, int *pHeight ) const = 0;
// Returns the current adapter in use
virtual int GetCurrentAdapter() const = 0;
// Are we using graphics?
virtual bool IsUsingGraphics() const = 0;
// Use this to spew information about the 3D layer
virtual void SpewDriverInfo() const = 0;
// What's the bit depth of the stencil buffer?
virtual int StencilBufferBits() const = 0;
// Are we using a mode that uses MSAA
virtual bool IsAAEnabled() const = 0;
// Which version string should we use when compiling shaders
virtual const char *GetShaderVersionString( RenderShaderType_t nType ) const = 0;
// Does a page flip
virtual void Present( ) = 0;
// Gamma ramp control
virtual void SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled ) = 0;
// Shader compilation
virtual IRenderShaderBuffer* CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ) = 0;
// Shader creation, destruction
virtual RenderShaderHandle_t CreateShader( RenderShaderType_t nType, IRenderShaderBuffer* pShaderBuffer ) = 0; virtual void DestroyShader( RenderShaderType_t nType, RenderShaderHandle_t hShader ) = 0;
// Defines input layouts
virtual RenderInputLayout_t CreateInputLayout( const char *pLayoutName, int nFieldCount, const RenderInputLayoutField_t *pFieldDescs ) = 0; virtual void DestroyInputLayout( RenderInputLayout_t hInputLayout ) = 0;
// Defines render target bind objects
// NOTE: Use RENDER_TARGET_BINDING_BACK_BUFFER for the back buffer
// Also note: If you need to re-use a buffer and render into it a second time,
// create a new render target binding to the same buffer. That will help sorting
virtual RenderTargetBinding_t CreateRenderTargetBinding( int nFlags, int nRenderTargetCount, const HRenderTexture *pRenderTargets, HRenderTexture hDepthStencilTexture ) = 0; RenderTargetBinding_t CreateRenderTargetBinding( int nFlags, HRenderTexture hRenderTarget, HRenderTexture hDepthStencilTexture ); virtual void DestroyRenderTargetBinding( RenderTargetBinding_t hBinding ) = 0;
// Utility methods to make shader creation simpler
// NOTE: For the utlbuffer version, use a binary buffer for a compiled shader
// and a text buffer for a source-code (.fxc) shader
RenderShaderHandle_t CreateShader( RenderShaderType_t nType, const char *pProgram, size_t nBufLen, const char *pShaderVersion ); RenderShaderHandle_t CreateShader( RenderShaderType_t nType, CUtlBuffer &buf, const char *pShaderVersion = NULL ); RenderShaderHandle_t CreateShader( RenderShaderType_t nType, const void *pCompiledProgram, size_t nBufLen );
// Creates render state objects
virtual RsRasterizerStateHandle_t FindOrCreateRasterizerState( const RsRasterizerStateDesc_t *pRsDesc ) = 0; virtual RsDepthStencilStateHandle_t FindOrCreateDepthStencilState( const RsDepthStencilStateDesc_t *pDsDesc ) = 0; virtual RsBlendStateHandle_t FindOrCreateBlendState( const RsBlendStateDesc_t *pBlendDesc ) = 0;
// Creates/destroys vertex + index buffers
// For CreateIndexBuffer, nMaxInstanceCount == 0 means we don't expect
// the buffer to be used w/ instanced rendering.
// mNaxInstanceCount == INT_MAX means we have no idea how many instances will be rendered
virtual HRenderBuffer CreateRenderBuffer( const char *pGroupName, const char *pResourceName, const RenderBufferDesc_t *pDescriptor, size_t nDataSize ) = 0; virtual void DestroyRenderBuffer( HRenderBuffer hBuffer ) = 0; virtual HRenderBuffer CreateVertexBuffer( RenderBufferType_t nType, const BufferDesc_t& desc ) = 0; virtual void DestroyVertexBuffer( HRenderBuffer hVertexBuffer ) = 0; virtual HRenderBuffer CreateIndexBuffer( RenderBufferType_t nType, const BufferDesc_t& desc, int nMaxInstanceCount = 0 ) = 0; virtual void DestroyIndexBuffer( HRenderBuffer hIndexBuffer ) = 0;
// Query buffer info
virtual void GetVertexBufferDesc( HRenderBuffer hVertexBuffer, BufferDesc_t *pDesc ) = 0; virtual void GetIndexBufferDesc( HRenderBuffer hIndexBuffer, BufferDesc_t *pDesc ) = 0;
// textures
virtual HRenderTexture FindOrCreateTexture( const char *pGroupName, const char *pResourceName, const TextureHeader_t *pDescriptor ) = 0;
// manage file-backed textures.
virtual HRenderTexture FindOrCreateFileTexture( const char *pFileName, RenderSystemAssetFileLoadMode_t nLoadMode = LOADMODE_ASYNCHRONOUS ) = 0; virtual HRenderTexture FindFileTexture( ResourceId_t nId, RenderSystemAssetFileLoadMode_t nLoadMode = LOADMODE_ASYNCHRONOUS ) = 0;
// Allows use of render contexts
virtual void EnableRenderContexts( bool bEnable ) = 0;
// render contexts
virtual IRenderContext *GetRenderContext( ) = 0; virtual void ReleaseRenderContext( IRenderContext *pContext ) = 0;
// submitting pre-built display lists
virtual void SubmitDisplayList( class CDisplayList *pCommandList ) =0;
// there is no release. These are automatically released when satisfied, and as far as the client is concerned, they are all gone after Present().
virtual CDependencyDescriptor *GetDependencyDescriptor( int nNumBatchesWhichWillBeSubmitted = 1, char const *pDebugString = NULL ) =0;
// create/destroy constant buffers
virtual ConstantBufferHandle_t CreateConstantBuffer( size_t nNumBytes ) { return NULL; }; virtual void DestroyConstantBuffer( ConstantBufferHandle_t hConstantBuffer ) {};
// Forces a device lost
virtual void ForceDeviceLost() = 0;
// Reads the contents of a texture
virtual void ReadTexturePixels( HRenderTexture hTexture, Rect_t *pSrcRect, Rect_t *pDstRect, void *pData, ImageFormat dstFormat, int nDstStride ) = 0; };
//-----------------------------------------------------------------------------
// Helper wrapper for IRenderShaderBuffer for reading precompiled shader files
// NOTE: This is meant to be instanced on the stack; so don't call Release!
//-----------------------------------------------------------------------------
class CUtlRenderShaderBuffer : public IRenderShaderBuffer { public: CUtlRenderShaderBuffer( CUtlBuffer &buf ) : m_pBuf( &buf ) {}
virtual size_t GetSize() const { return m_pBuf->TellMaxPut(); }
virtual const void* GetBits() const { return m_pBuf->Base(); }
virtual void Release() { Assert( 0 ); }
private: CUtlBuffer *m_pBuf; };
//-----------------------------------------------------------------------------
// Inline methods of IRenderDevice
//-----------------------------------------------------------------------------
inline RenderTargetBinding_t IRenderDevice::CreateRenderTargetBinding( int nFlags, HRenderTexture hRenderTarget, HRenderTexture hDepthStencilTexture ) { return CreateRenderTargetBinding( nFlags, 1, &hRenderTarget, hDepthStencilTexture ); }
inline RenderShaderHandle_t IRenderDevice::CreateShader( RenderShaderType_t nType, const char *pProgram, size_t nBufLen, const char *pShaderVersion ) { RenderShaderHandle_t hShader = RENDER_SHADER_HANDLE_INVALID; IRenderShaderBuffer* pShaderBuffer = CompileShader( pProgram, nBufLen, pShaderVersion ); if ( pShaderBuffer ) { hShader = CreateShader( nType, pShaderBuffer ); pShaderBuffer->Release(); } return hShader; }
inline RenderShaderHandle_t IRenderDevice::CreateShader( RenderShaderType_t nType, CUtlBuffer &buf, const char *pShaderVersion ) { // NOTE: Text buffers are assumed to have source-code shader files
// Binary buffers are assumed to have compiled shader files
if ( buf.IsText() ) { Assert( pShaderVersion ); return CreateShader( nType, (const char *)buf.Base(), buf.TellMaxPut(), pShaderVersion ); }
CUtlRenderShaderBuffer shaderBuffer( buf ); return CreateShader( nType, &shaderBuffer ); }
inline RenderShaderHandle_t IRenderDevice::CreateShader( RenderShaderType_t nType, const void *pCompiledProgram, size_t nBufLen ) { Assert( nBufLen == ( int )nBufLen ); // make sure we're not trimming 4Gb+ sizes
CUtlBuffer tmpBuf( pCompiledProgram, ( int )nBufLen, CUtlBuffer::READ_ONLY ); return CreateShader( nType, tmpBuf, NULL ); }
#endif // IRENDERDEVICE_H
|