//============ Copyright (c) Valve Corporation, All rights reserved. ============ // // cglmtex.h // GLMgr textures // //=============================================================================== #ifndef CGLMTEX_H #define CGLMTEX_H #pragma once #ifdef OSX #include "glmgr/glmgrbasics.h" #endif #include "tier1/utlhash.h" #include "tier1/utlmap.h" //=============================================================================== // forward declarations class GLMContext; class GLMTester; class CGLMTexLayoutTable; class CGLMTex; class CGLMFBO; class IDirect3DSurface9; //=============================================================================== struct GLMTexFormatDesc { const char *m_formatSummary; // for debug visibility D3DFORMAT m_d3dFormat; // what D3D knows it as; see public/bitmap/imageformat.h GLenum m_glIntFormat; // GL internal format GLenum m_glIntFormatSRGB; // internal format if SRGB flavor GLenum m_glDataFormat; // GL data format GLenum m_glDataType; // GL data type int m_chunkSize; // 1 or 4 - 4 is used for compressed textures int m_bytesPerSquareChunk; // how many bytes for the smallest quantum (m_chunkSize x m_chunkSize) // this description lets us calculate size cleanly without conditional logic for compression }; const GLMTexFormatDesc *GetFormatDesc( D3DFORMAT format ); //=============================================================================== // utility function for generating slabs of texels. mostly for test. typedef struct { // in D3DFORMAT m_format; void *m_dest; // dest address int m_chunkCount; // square chunk count (single texels or compressed blocks) int m_byteCountLimit; // caller expectation of max number of bytes to write out float r,g,b,a; // color desired // out int m_bytesWritten; } GLMGenTexelParams; // return true if successful bool GLMGenTexels( GLMGenTexelParams *params ); //=============================================================================== struct GLMTexLayoutSlice { int m_xSize,m_ySize,m_zSize; //texel dimensions of this slice int m_storageOffset; //where in the storage slab does this slice live int m_storageSize; //how much storage does this slice occupy }; enum EGLMTexFlags { kGLMTexMipped = 0x01, kGLMTexMippedAuto = 0x02, kGLMTexRenderable = 0x04, kGLMTexIsStencil = 0x08, kGLMTexIsDepth = 0x10, kGLMTexSRGB = 0x20, kGLMTexUnused = 0x40, // UNUSED kGLMTexMultisampled = 0x80, // has an RBO backing it. Cannot combine with Mipped, MippedAuto. One slice maximum, only targeting GL_TEXTURE_2D. // actually not 100% positive on the mipmapping, the RBO itself can't be mipped, but the resulting texture could // have mipmaps generated. }; //=============================================================================== struct GLMTexLayoutKey { // input values: held const, these are the hash key for the form map GLenum m_texGLTarget; // flavor of texture: GL_TEXTURE_2D, GL_TEXTURE_3D, GLTEXTURE_CUBE_MAP D3DFORMAT m_texFormat; // D3D texel format unsigned long m_texFlags; // mipped, autogen mips, render target, ... ? unsigned long m_texSamples; // zero for a plain tex, 2/4/6/8 for "MSAA tex" (RBO backed) int m_xSize,m_ySize,m_zSize; // size of base mip }; bool LessFunc_GLMTexLayoutKey( const GLMTexLayoutKey &a, const GLMTexLayoutKey &b ); #define GLM_TEX_MAX_MIPS 14 #define GLM_TEX_MAX_FACES 6 #define GLM_TEX_MAX_SLICES (GLM_TEX_MAX_MIPS * GLM_TEX_MAX_FACES) struct GLMTexLayout { char *m_layoutSummary; // for debug visibility // const inputs used for hashing GLMTexLayoutKey m_key; // refcount int m_refCount; // derived values: GLMTexFormatDesc *m_format; // format specific info int m_mipCount; // derived by starying at base size and working down towards 1x1 int m_faceCount; // 1 for 2d/3d, 6 for cubemap int m_sliceCount; // product of faces and mips int m_storageTotalSize; // size of storage slab required // slice array GLMTexLayoutSlice m_slices[0]; // dynamically allocated 2-d array [faces][mips] }; class CGLMTexLayoutTable { public: CGLMTexLayoutTable(); GLMTexLayout *NewLayoutRef( GLMTexLayoutKey *key ); // pass in a pointer to layout key - receive ptr to completed layout void DelLayoutRef( GLMTexLayout *layout ); // pass in pointer to completed layout. refcount is dropped. void DumpStats( void ); protected: CUtlMap< GLMTexLayoutKey, GLMTexLayout* > m_layoutMap; }; //=============================================================================== // a sampler specifies desired state for drawing on a given sampler index // this is the combination of a texture choice and a set of sampler parameters // see http://msdn.microsoft.com/en-us/library/bb172602(VS.85).aspx struct GLMTexSamplingParams { GLenum m_addressModes[3]; // S, T, R GLfloat m_borderColor[4]; // R,G,B,A GLenum m_magFilter; GLenum m_minFilter; GLfloat m_mipmapBias; GLint m_minMipLevel; GLint m_maxMipLevel; GLint m_maxAniso; GLenum m_compareMode; // only used for depth and stencil type textures bool m_srgb; // srgb texture read... }; struct GLMTexLockParams { // input params which identify the slice of interest CGLMTex *m_tex; int m_face; int m_mip; // identifies the region of the slice GLMRegion m_region; // tells GLM to force re-read of the texels back from GL // i.e. "I know I stepped on those texels with a draw or blit - the GLM copy is stale" bool m_readback; }; struct GLMTexLockDesc { GLMTexLockParams m_req; // form of the lock request bool m_active; // set true at lock time. cleared at unlock time. int m_sliceIndex; // which slice in the layout int m_sliceBaseOffset; // where is that in the texture data int m_sliceRegionOffset; // offset to the start (lowest address corner) of the region requested }; //=============================================================================== #define GLM_SAMPLER_COUNT 16 typedef CBitVec CTexBindMask; enum EGLMTexSliceFlag { kSliceValid = 0x01, // slice has been teximage'd in whole at least once - set to 0 initially kSliceStorageValid = 0x02, // if backing store is available, this slice's data is a valid copy - set to 0 initially kSliceLocked = 0x04, // are one or more locks outstanding on this slice kSliceFullyDirty = 0x08, // does the slice need to be fully downloaded at unlock time (disregard dirty rects) }; class CGLMTex { public: void Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut, int *zStrideOut ); void Unlock( GLMTexLockParams *params ); protected: friend class GLMContext; // only GLMContext can make CGLMTex objects friend class GLMTester; friend class CGLMFBO; friend class IDirect3DDevice9; friend class IDirect3DBaseTexture9; friend class IDirect3DTexture9; friend class IDirect3DSurface9; friend class IDirect3DCubeTexture9; friend class IDirect3DVolumeTexture9; CGLMTex( GLMContext *ctx, GLMTexLayout *layout, GLMTexSamplingParams *sampling, const char *debugLabel = NULL ); ~CGLMTex( ); int CalcSliceIndex( int face, int mip ); void CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut ); void ApplySamplingParams( GLMTexSamplingParams *params, bool noCheck=FALSE ); void ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice=true ); void WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice=true, bool noDataWrite=false ); // last param lets us send NULL data ptr (only legal with uncompressed formats, beware) // this helps out ResetSRGB. void ResetSRGB( bool srgb, bool noDataWrite ); // re-specify texture format to match desired sRGB form // noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's GLMTexLayout *m_layout; // layout of texture (shared across all tex with same layout) int m_minActiveMip;//index of lowest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL. int m_maxActiveMip;//index of highest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL. GLMTexSamplingParams m_sampling; // mirror of sampling params currently embodied in the texture // (consult this at draw time, in order to know if changes need to be made) GLMContext *m_ctx; // link back to parent context GLuint m_texName; // name of this texture in the context bool m_texClientStorage; // was CS selecetd for texture bool m_texPreloaded; // has it been kicked into VRAM with GLMContext::PreloadTex yet GLuint m_rboName; // name of MSAA RBO backing the tex if MSAA enabled (or zero) bool m_rboDirty; // has RBO been drawn on - i.e. needs to be blitted back to texture if texture is going to be sampled from CTexBindMask m_bindPoints; // true for each place in the parent ctx where currently // bound (indexed via EGLMTexCtxBindingIndex) int m_rtAttachCount; // how many RT's have this texture attached somewhere char *m_backing; // backing storage if available int m_lockCount; // lock reqs are stored in the GLMContext for tracking CUtlVector m_sliceFlags; char *m_debugLabel; // strdup() of debugLabel passed in, or NULL }; #endif