#ifndef __PIXEL_HPP__ #define __PIXEL_HPP__ /*==========================================================================; * * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved. * * File: pixel.hpp * Content: Utility class for working with pixel formats * * ***************************************************************************/ // includes #include "d3dobj.hpp" struct IHVFormatInfo { D3DFORMAT m_Format; DWORD m_BPP; IHVFormatInfo *m_pNext; }; // This is a utility class that implements useful helpers for // allocating and accessing various pixel formats. All methods // are static and hence should be accessed as follows: // e.g. CPixel::LockOffset(...) // class CPixel { public: // Allocate helpers // Determine the amount of memory that is needed to // allocate various things.. static UINT ComputeSurfaceSize(UINT cpWidth, UINT cpHeight, D3DFORMAT Format); static UINT ComputeVolumeSize(UINT cpWidth, UINT cpHeight, UINT cpDepth, D3DFORMAT Format); static UINT ComputeMipMapSize(UINT cpWidth, UINT cpHeight, UINT cLevels, D3DFORMAT Format); static UINT ComputeMipVolumeSize(UINT cpWidth, UINT cpHeight, UINT cpDepth, UINT cLevels, D3DFORMAT Format); // Lock helpers // Given a surface desc, a level, and pointer to // bits (pBits in the LockedRectData) and a sub-rect, // this will fill in the pLockedRectData structure static void ComputeMipMapOffset(const D3DSURFACE_DESC *pDescTopLevel, UINT iLevel, BYTE *pBits, CONST RECT *pRect, D3DLOCKED_RECT *pLockedRectData); // MipVolume version of ComputeMipMapOffset static void ComputeMipVolumeOffset(const D3DVOLUME_DESC *pDescTopLevel, UINT iLevel, BYTE *pBits, CONST D3DBOX *pBox, D3DLOCKED_BOX *pLockedBoxData); // Surface version of ComputeMipMapOffset static void ComputeSurfaceOffset(const D3DSURFACE_DESC *pDesc, BYTE *pBits, CONST RECT *pRect, D3DLOCKED_RECT *pLockedRectData); // Is this a supported format? static BOOL IsSupported(D3DRESOURCETYPE Type, D3DFORMAT Format); // Is this a IHV non-standard format? i.e. do // we know the number of bytes per pixel? static BOOL IsIHVFormat(D3DFORMAT Format); // Is this a Z format that the user can create? static BOOL IsEnumeratableZ (D3DFORMAT Format); // Is this a Z format that needs mapping b4 sending // to the driver? static BOOL IsMappedDepthFormat(D3DFORMAT Format); // All depth formats other than D16 are currently // defined to be non-lockable. This function will // return FALSE for: // non-Z formats // D16_LOCKABLE // IHV formats static BOOL IsNonLockableZ(D3DFORMAT Format); // Pixel Stride will return negative for DXT formats // Call AdjustForDXT to work with things at the block level static UINT ComputePixelStride(D3DFORMAT Format); // This will adjust cbPixel // to pixels per block; and width and height will // be adjusted to pixels. Assumes the IsDXT(cbPixel). static void AdjustForDXT(UINT *pcpWidth, UINT *pcpHeight, UINT *pcbPixel); // Adjust parameters for VolumeDXT static void AdjustForVolumeDXT(UINT *pcpWidth, UINT *pcpHeight, UINT *pcpDepth, UINT *pcbPixel); // returns TRUE if cbPixel is "negative" i.e. DXT/V group static BOOL IsDXT(UINT cbPixel); // returns TRUE if format is one of the DXT/V group static BOOL IsDXT(D3DFORMAT Format); // returns TRUE if format is one of the DXV family static BOOL IsVolumeDXT(D3DFORMAT Format); // returns TRUE if format has stencil bits static BOOL HasStencilBits(D3DFORMAT Format); // returns TRUE if format is paletted static BOOL IsPaletted(D3DFORMAT Format); // Helpers for validation for DXTs. static BOOL IsValidRect(D3DFORMAT Format, UINT Width, UINT Height, const RECT *pRect); static BOOL IsValidBox(D3DFORMAT Format, UINT Width, UINT Height, UINT Depth, const D3DBOX *pBox); // Needs 4x4 Rules (DXT/DXVs) static BOOL Requires4X4(D3DFORMAT Format); // Detection for "real" FourCC formats static BOOL IsFourCC(D3DFORMAT Format); static D3DFORMAT SuppressAlphaChannel(D3DFORMAT Format); static UINT BytesPerPixel(D3DFORMAT Format); // Register format for later lookup static HRESULT Register(D3DFORMAT Format, DWORD BPP); // Cleanup registry static void Cleanup(); private: // Internal functions static UINT ComputeSurfaceStride(UINT cpWidth, UINT cbPixel); static UINT ComputeSurfaceSize(UINT cpWidth, UINT cpHeight, UINT cbPixel); static IHVFormatInfo *m_pFormatList; }; // CPixel #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsIHVFormat" inline BOOL CPixel::IsIHVFormat(D3DFORMAT Format) { // If we know the number of bytes per // pixel; it's a non-IHV format if (BytesPerPixel(Format) != 0) return FALSE; // Must be an IHV format return TRUE; } // IsIHVFormat #undef DPF_MODNAME #define DPF_MODNAME "CPixel::ComputeSurfaceOffset" inline void CPixel::ComputeSurfaceOffset(const D3DSURFACE_DESC *pDesc, BYTE *pBits, CONST RECT *pRect, D3DLOCKED_RECT *pLockedRectData) { ComputeMipMapOffset(pDesc, 0, pBits, pRect, pLockedRectData); } // ComputeSurfaceOffset #undef DPF_MODNAME #define DPF_MODNAME "CPixel::ComputeSurfaceSize" inline UINT CPixel::ComputeSurfaceSize(UINT cpWidth, UINT cpHeight, D3DFORMAT Format) { UINT cbPixel = ComputePixelStride(Format); // Adjust pixel->block if necessary BOOL isDXT = IsDXT(cbPixel); if (isDXT) { AdjustForDXT(&cpWidth, &cpHeight, &cbPixel); } return ComputeSurfaceSize(cpWidth, cpHeight, cbPixel); } // ComputeSurfaceSize #undef DPF_MODNAME #define DPF_MODNAME "CPixel::AdjustForDXT" inline void CPixel::AdjustForDXT(UINT *pcpWidth, UINT *pcpHeight, UINT *pcbPixel) { DXGASSERT(pcbPixel); DXGASSERT(pcpWidth); DXGASSERT(pcpHeight); DXGASSERT(IsDXT(*pcbPixel)); // Adjust width and height for DXT formats to be in blocks // instead of pixels. Blocks are 4x4 pixels. *pcpWidth = (*pcpWidth + 3) / 4; *pcpHeight = (*pcpHeight + 3) / 4; // Negate the pcbPixel to determine bytes per block *pcbPixel *= -1; // We only know of two DXT formats right now... DXGASSERT(*pcbPixel == 8 || *pcbPixel == 16); } // CPixel::AdjustForDXT #undef DPF_MODNAME #define DPF_MODNAME "CPixel::AdjustForVolumeDXT" inline void CPixel::AdjustForVolumeDXT(UINT *pcpWidth, UINT *pcpHeight, UINT *pcpDepth, UINT *pcbPixel) { DXGASSERT(pcbPixel); DXGASSERT(pcpWidth); DXGASSERT(pcpHeight); DXGASSERT(IsDXT(*pcbPixel)); // Adjust width, height, depth for DXT formats to be in blocks // instead of pixels. Blocks are 4x4x4 pixels. *pcpWidth = (*pcpWidth + 3) / 4; *pcpHeight = (*pcpHeight + 3) / 4; *pcpDepth = (*pcpDepth + 3) / 4; // Negate the pcbPixel to determine bytes per block *pcbPixel *= -1; // We only know of two DXV formats right now... DXGASSERT(*pcbPixel == 32 || *pcbPixel == 64); } // CPixel::AdjustForVolumeDXT #undef DPF_MODNAME #define DPF_MODNAME "CPixel::ComputeVolumeSize" inline UINT CPixel::ComputeVolumeSize(UINT cpWidth, UINT cpHeight, UINT cpDepth, D3DFORMAT Format) { UINT cbPixel = ComputePixelStride(Format); if (IsDXT(cbPixel)) { if (IsVolumeDXT(Format)) { AdjustForVolumeDXT(&cpWidth, &cpHeight, &cpDepth, &cbPixel); } else { AdjustForDXT(&cpWidth, &cpHeight, &cbPixel); } } return cpDepth * ComputeSurfaceSize(cpWidth, cpHeight, cbPixel); } // ComputeVolumeSize #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsSupported" inline BOOL CPixel::IsSupported(D3DRESOURCETYPE Type, D3DFORMAT Format) { UINT cbPixel = ComputePixelStride(Format); if (cbPixel == 0) { return FALSE; } else if (IsVolumeDXT(Format)) { if (Type == D3DRTYPE_VOLUMETEXTURE) return TRUE; else return FALSE; } else { return TRUE; } } // IsSupported #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsDXT(cbPixel)" // returns TRUE if cbPixel is "negative" inline BOOL CPixel::IsDXT(UINT cbPixel) { if (((INT)cbPixel) < 0) return TRUE; else return FALSE; } // IsDXT #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsDXT(format)" // returns TRUE if this is a linear format // i.e. DXT or DXV inline BOOL CPixel::IsDXT(D3DFORMAT Format) { // CONSIDER: This is a duplication of Requires4x4 function switch (Format) { // normal DXTs case D3DFMT_DXT1: case D3DFMT_DXT2: case D3DFMT_DXT3: case D3DFMT_DXT4: case D3DFMT_DXT5: #ifdef VOLUME_DXT // Volume dxts case D3DFMT_DXV1: case D3DFMT_DXV2: case D3DFMT_DXV3: case D3DFMT_DXV4: case D3DFMT_DXV5: #endif //VOLUME_DXT return TRUE; } return FALSE; } // IsDXT #undef DPF_MODNAME #define DPF_MODNAME "CPixel::Requires4X4" // returns TRUE for formats that have 4x4 rules inline BOOL CPixel::Requires4X4(D3DFORMAT Format) { switch (Format) { // normal DXTs case D3DFMT_DXT1: case D3DFMT_DXT2: case D3DFMT_DXT3: case D3DFMT_DXT4: case D3DFMT_DXT5: #ifdef VOLUME_DXT // Volume dxts case D3DFMT_DXV1: case D3DFMT_DXV2: case D3DFMT_DXV3: case D3DFMT_DXV4: case D3DFMT_DXV5: #endif //VOLUME_DXT return TRUE; } return FALSE; } // Requires4X4 #undef DPF_MODNAME #define DPF_MODNAME "CPixel::HasStencilBits" // returns TRUE if format has stencil bits inline BOOL CPixel::HasStencilBits(D3DFORMAT Format) { switch (Format) { case D3DFMT_S1D15: case D3DFMT_D15S1: case D3DFMT_S8D24: case D3DFMT_D24S8: case D3DFMT_X4S4D24: case D3DFMT_D24X4S4: return TRUE; } return FALSE; } // HasStencilBits #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsVolumeDXT" // returns TRUE if format is one of the DXTV family inline BOOL CPixel::IsVolumeDXT(D3DFORMAT Format) { #ifdef VOLUME_DXT if (Format >= D3DFMT_DXV1 && Format <= D3DFMT_DXV5) return TRUE; else #endif //VOLUME_DXT return FALSE; } // IsVolumeDXT #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsPaletted" // returns TRUE if Format is paletted inline BOOL CPixel::IsPaletted(D3DFORMAT Format) { return (Format == D3DFMT_P8) || (Format == D3DFMT_A8P8); } // IsPaletted #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsFourCC" // returns TRUE if Format is a FourCC inline BOOL CPixel::IsFourCC(D3DFORMAT Format) { DWORD dwFormat = (DWORD)Format; if (HIBYTE(LOWORD(dwFormat)) != 0) { // FourCC formats are non-zero for in their // third byte. return TRUE; } else { return FALSE; } } // IsFourCC #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsEnumeratableZ" // IsEnumeratableZ // // We only want to enumerate D16 and the Z formats. We have to know // about the others so we have to keep them in our list, but we added this // function so we'd never enumerate them to the app. inline BOOL CPixel::IsEnumeratableZ (D3DFORMAT Format) { if ((Format == D3DFMT_D16) || (Format == D3DFMT_D16_LOCKABLE) || (Format == D3DFMT_D15S1) || (Format == D3DFMT_D24X8) || (Format == D3DFMT_D24X4S4) || (Format == D3DFMT_D24S8) || (Format == D3DFMT_D32)) { return TRUE; } // IHV formats are creatable; so we let them pass if (IsIHVFormat(Format)) { return TRUE; } return FALSE; } // IsEnumeratableZ #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsMappedDepthFormat" // Is this a Z format that needs mapping b4 sending // to the driver? inline BOOL CPixel::IsMappedDepthFormat(D3DFORMAT Format) { // D16_LOCKABLE and D32 do not need // mapping if ((Format == D3DFMT_D16) || (Format == D3DFMT_D15S1) || (Format == D3DFMT_D24X4S4) || (Format == D3DFMT_D24X8) || (Format == D3DFMT_D24S8)) { return TRUE; } return FALSE; } // IsMappedDepthFormat #undef DPF_MODNAME #define DPF_MODNAME "CPixel::IsNonLockableZ" // All depth formats other than D16 are currently // defined to be non-lockable. This function will // return FALSE for: // non-Z formats // D16_LOCKABLE // IHV formats inline BOOL CPixel::IsNonLockableZ(D3DFORMAT Format) { if ((Format == D3DFMT_D16) || (Format == D3DFMT_D15S1) || (Format == D3DFMT_D24X8) || (Format == D3DFMT_D24S8) || (Format == D3DFMT_D24X4S4) || (Format == D3DFMT_D32)) { return TRUE; } // D16_LOCKABLE is lockable; and other // formats are either lockable i.e. IHV or // are not a Z format. return FALSE; } // IsNonLockableZ #endif // __PIXEL_HPP__