1378 lines
42 KiB
C++
1378 lines
42 KiB
C++
|
/*==========================================================================;
|
||
|
*
|
||
|
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: cubemap.cpp
|
||
|
* Content: Implementation of the CCubeMap class.
|
||
|
*
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
#include "ddrawpr.h"
|
||
|
#include "cubemap.hpp"
|
||
|
#include "cubesurf.hpp"
|
||
|
#include "d3di.hpp"
|
||
|
#include "resource.inl"
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::Create"
|
||
|
|
||
|
// Static class function for creating a cube-map object.
|
||
|
// (Because it is static; it doesn't have a this pointer.)
|
||
|
//
|
||
|
// We do all parameter checking here to reduce the overhead
|
||
|
// in the constructor which is called by the internal Clone
|
||
|
// method which is used by resource management as part of the
|
||
|
// performance critical download operation.
|
||
|
|
||
|
|
||
|
HRESULT CCubeMap::Create(CBaseDevice *pDevice,
|
||
|
DWORD cpEdge,
|
||
|
DWORD cLevels,
|
||
|
DWORD Usage,
|
||
|
D3DFORMAT UserFormat,
|
||
|
D3DPOOL Pool,
|
||
|
IDirect3DCubeTexture8 **ppCubeMap)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Do parameter checking here
|
||
|
if (!VALID_PTR_PTR(ppCubeMap))
|
||
|
{
|
||
|
DPF_ERR("Bad parameter passed for ppSurface for creating a cubemap");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Zero-out return parameter
|
||
|
*ppCubeMap = NULL;
|
||
|
|
||
|
// Check if format is valid
|
||
|
hr = Validate(pDevice,
|
||
|
D3DRTYPE_CUBETEXTURE,
|
||
|
Pool,
|
||
|
Usage,
|
||
|
UserFormat);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// VerifyFormat does it's own DPFing
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Infer internal usage flags
|
||
|
Usage = InferUsageFlags(Pool, Usage, UserFormat);
|
||
|
|
||
|
// Expand cLevels if necessary
|
||
|
if (cLevels == 0)
|
||
|
{
|
||
|
// See if HW can mip
|
||
|
if ( (Pool != D3DPOOL_SCRATCH) && (!(pDevice->GetD3DCaps()->TextureCaps &
|
||
|
D3DPTEXTURECAPS_MIPCUBEMAP)))
|
||
|
{
|
||
|
// Can't mip so use 1
|
||
|
cLevels = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Determine number of levels
|
||
|
cLevels = ComputeLevels(cpEdge);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start parameter checking
|
||
|
|
||
|
if (cLevels > 32)
|
||
|
{
|
||
|
DPF_ERR("No more than 32 levels are supported for a cubemap texture");
|
||
|
|
||
|
// This limitation is based on the number of
|
||
|
// bits that we have allocated for iLevel in
|
||
|
// some of the supporting classes.
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Check if the device supports mipped cubemaps
|
||
|
if (cLevels > 1)
|
||
|
{
|
||
|
if ((cpEdge >> (cLevels - 1)) == 0)
|
||
|
{
|
||
|
DPF_ERR("Too many levels for Cube Texture of this size.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
D3DFORMAT RealFormat = UserFormat;
|
||
|
|
||
|
if (Pool != D3DPOOL_SCRATCH)
|
||
|
{
|
||
|
// Check size constraints for cubemap
|
||
|
if (pDevice->GetD3DCaps()->TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2)
|
||
|
{
|
||
|
if (!IsPowerOfTwo(cpEdge))
|
||
|
{
|
||
|
DPF_ERR("Device requires that edge must be power of two for cube-maps");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check texture size restrictions
|
||
|
if (cpEdge > pDevice->GetD3DCaps()->MaxTextureWidth)
|
||
|
{
|
||
|
DPF_ERR("Texture width is larger than what the device supports. Cube Texture creation fails.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (cpEdge > pDevice->GetD3DCaps()->MaxTextureHeight)
|
||
|
{
|
||
|
DPF_ERR("Texture height is larger than what the device supports. Cube Texture creation fails.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Check that the device supports cubemaps
|
||
|
if (!(pDevice->GetD3DCaps()->TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
|
||
|
{
|
||
|
DPF_ERR("Device doesn't support Cube Texture; Cube Texture creation failed.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Check if the device supports mipped cubemaps
|
||
|
if (cLevels > 1)
|
||
|
{
|
||
|
if (!(pDevice->GetD3DCaps()->TextureCaps &
|
||
|
D3DPTEXTURECAPS_MIPCUBEMAP))
|
||
|
{
|
||
|
DPF_ERR("Device doesn't support mipped cube textures; creation failed.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Map Depth/Stencil formats; returns no change if no
|
||
|
// mapping is needed
|
||
|
RealFormat = pDevice->MapDepthStencilFormat(UserFormat);
|
||
|
}
|
||
|
|
||
|
// Size may need to be 4x4
|
||
|
if (CPixel::Requires4X4(UserFormat))
|
||
|
{
|
||
|
if (cpEdge & 3)
|
||
|
{
|
||
|
DPF_ERR("DXT Formats require edge to be a multiples of 4. Cube Texture creation fails.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Validate against zero width/height
|
||
|
if (cpEdge == 0)
|
||
|
{
|
||
|
DPF_ERR("Edge must be non-zero. Cube Texture creation fails.");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Allocate a new CubeMap object and return it
|
||
|
CCubeMap *pCubeMap = new CCubeMap(pDevice,
|
||
|
cpEdge,
|
||
|
cLevels,
|
||
|
Usage,
|
||
|
UserFormat,
|
||
|
RealFormat,
|
||
|
Pool,
|
||
|
REF_EXTERNAL,
|
||
|
&hr);
|
||
|
if (pCubeMap == NULL)
|
||
|
{
|
||
|
DPF_ERR("Out of Memory creating cubemap");
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPF_ERR("Error during initialization of cubemap");
|
||
|
pCubeMap->ReleaseImpl();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// We're done; just return the object
|
||
|
*ppCubeMap = pCubeMap;
|
||
|
|
||
|
return hr;
|
||
|
} // static Create
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::CCubeMap"
|
||
|
|
||
|
// Constructor the cube map class
|
||
|
CCubeMap::CCubeMap(CBaseDevice *pDevice,
|
||
|
DWORD cpEdge,
|
||
|
DWORD cLevels,
|
||
|
DWORD Usage,
|
||
|
D3DFORMAT UserFormat,
|
||
|
D3DFORMAT RealFormat,
|
||
|
D3DPOOL UserPool,
|
||
|
REF_TYPE refType,
|
||
|
HRESULT *phr
|
||
|
) :
|
||
|
CBaseTexture(pDevice, cLevels, UserPool, UserFormat, refType),
|
||
|
m_prgCubeSurfaces(NULL),
|
||
|
m_rgbPixels(NULL),
|
||
|
m_IsAnyFaceDirty(TRUE)
|
||
|
{
|
||
|
// Sanity check
|
||
|
DXGASSERT(phr);
|
||
|
DXGASSERT(cLevels <= 32);
|
||
|
|
||
|
// Initialize basic structures
|
||
|
m_prgCubeSurfaces = NULL;
|
||
|
m_rgbPixels = NULL;
|
||
|
m_desc.Format = RealFormat;
|
||
|
m_desc.Pool = UserPool;
|
||
|
m_desc.Usage = Usage;
|
||
|
m_desc.Type = D3DRTYPE_CUBETEXTURE;
|
||
|
m_desc.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||
|
m_desc.Width = cpEdge;
|
||
|
m_desc.Height = cpEdge;
|
||
|
|
||
|
// Initialize ourselves to all dirty
|
||
|
for (DWORD iFace = 0; iFace < CUBEMAP_MAXFACES; iFace++)
|
||
|
{
|
||
|
m_IsFaceCleanArray [iFace] = FALSE;
|
||
|
m_IsFaceAllDirtyArray[iFace] = TRUE;
|
||
|
}
|
||
|
|
||
|
// We assume that we start out dirty
|
||
|
DXGASSERT(IsDirty());
|
||
|
|
||
|
// We always have 6 faces now
|
||
|
DWORD cFaces = 6;
|
||
|
|
||
|
// Allocate Pixel Data
|
||
|
m_cbSingleFace = CPixel::ComputeMipMapSize(cpEdge,
|
||
|
cpEdge,
|
||
|
cLevels,
|
||
|
RealFormat);
|
||
|
|
||
|
// Round up to nearest 32 for alignment
|
||
|
m_cbSingleFace += 31;
|
||
|
m_cbSingleFace &= ~(31);
|
||
|
|
||
|
m_desc.Size = m_cbSingleFace * cFaces;
|
||
|
|
||
|
// Allocate Pixel Data for SysMem or D3DManaged cases
|
||
|
if (IS_D3D_ALLOCATED_POOL(UserPool) ||
|
||
|
IsTypeD3DManaged(Device(), D3DRTYPE_CUBETEXTURE, UserPool))
|
||
|
{
|
||
|
m_rgbPixels = new BYTE[m_desc.Size];
|
||
|
|
||
|
if (m_rgbPixels == NULL)
|
||
|
{
|
||
|
*phr = E_OUTOFMEMORY;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create the DDSURFACEINFO array and CreateSurfaceData object
|
||
|
DXGASSERT(cLevels <= 32);
|
||
|
|
||
|
DDSURFACEINFO SurfInfo[6 * 32];
|
||
|
ZeroMemory(SurfInfo, sizeof(SurfInfo));
|
||
|
|
||
|
D3D8_CREATESURFACEDATA CreateSurfaceData;
|
||
|
ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
|
||
|
|
||
|
// Set up the basic information
|
||
|
CreateSurfaceData.hDD = pDevice->GetHandle();
|
||
|
CreateSurfaceData.pSList = &SurfInfo[0];
|
||
|
CreateSurfaceData.dwSCnt = cLevels * cFaces;
|
||
|
CreateSurfaceData.Type = D3DRTYPE_CUBETEXTURE;
|
||
|
CreateSurfaceData.dwUsage = m_desc.Usage;
|
||
|
CreateSurfaceData.Format = RealFormat;
|
||
|
CreateSurfaceData.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||
|
CreateSurfaceData.Pool = DetermineCreationPool(Device(),
|
||
|
D3DRTYPE_CUBETEXTURE,
|
||
|
Usage,
|
||
|
UserPool);
|
||
|
|
||
|
// Iterate of each face/level to create the individual level
|
||
|
// data
|
||
|
for (iFace = 0; iFace < cFaces; iFace++)
|
||
|
{
|
||
|
// Start width and height at the full size
|
||
|
cpEdge = m_desc.Width;
|
||
|
DXGASSERT(m_desc.Width == m_desc.Height);
|
||
|
|
||
|
for (DWORD iLevel = 0; iLevel < cLevels; iLevel++)
|
||
|
{
|
||
|
int index = (iFace * cLevels) + iLevel;
|
||
|
|
||
|
// Fill in the relevant information
|
||
|
DXGASSERT(cpEdge >= 1);
|
||
|
SurfInfo[index].cpWidth = cpEdge;
|
||
|
SurfInfo[index].cpHeight = cpEdge;
|
||
|
|
||
|
// If we allocated the memory, pass down
|
||
|
// the sys-mem pointers
|
||
|
if (m_rgbPixels)
|
||
|
{
|
||
|
D3DLOCKED_RECT lock;
|
||
|
ComputeCubeMapOffset(iFace,
|
||
|
iLevel,
|
||
|
NULL, // pRect
|
||
|
&lock);
|
||
|
|
||
|
SurfInfo[index].pbPixels = (BYTE*)lock.pBits;
|
||
|
SurfInfo[index].iPitch = lock.Pitch;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Scale width and height down for each level
|
||
|
cpEdge >>= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Allocate array of pointers to CubeSurfaces
|
||
|
m_prgCubeSurfaces = new CCubeSurface*[cLevels*cFaces];
|
||
|
if (m_prgCubeSurfaces == NULL)
|
||
|
{
|
||
|
*phr = E_OUTOFMEMORY;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Zero the memory for safe cleanup
|
||
|
ZeroMemory(m_prgCubeSurfaces,
|
||
|
sizeof(*m_prgCubeSurfaces) * cLevels * cFaces);
|
||
|
|
||
|
if (UserPool != D3DPOOL_SCRATCH)
|
||
|
{
|
||
|
// Call the HAL to create this surface
|
||
|
*phr = pDevice->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
|
||
|
if (FAILED(*phr))
|
||
|
return;
|
||
|
|
||
|
// NOTE: any failures after this point needs to free up some
|
||
|
// kernel handles
|
||
|
|
||
|
// Remember what pool we really got
|
||
|
m_desc.Pool = CreateSurfaceData.Pool;
|
||
|
|
||
|
// We need to remember the handles from the top most
|
||
|
// level of the mip-map
|
||
|
SetKernelHandle(SurfInfo[0].hKernelHandle);
|
||
|
}
|
||
|
|
||
|
// Create and Initialize each CubeLevel
|
||
|
for (iFace = 0; iFace < cFaces; iFace++)
|
||
|
{
|
||
|
for (DWORD iLevel = 0; iLevel < cLevels; iLevel++)
|
||
|
{
|
||
|
int index = (iFace * cLevels) + iLevel;
|
||
|
|
||
|
DXGASSERT((BYTE)iFace == iFace);
|
||
|
DXGASSERT((BYTE)iLevel == iLevel);
|
||
|
|
||
|
// Create the appropriate cube-level depending on type
|
||
|
|
||
|
// Is this a sys-mem surface; could be d3d managed
|
||
|
if (IS_D3D_ALLOCATED_POOL(m_desc.Pool))
|
||
|
{
|
||
|
m_prgCubeSurfaces[index] =
|
||
|
new CCubeSurface(this,
|
||
|
(BYTE)iFace,
|
||
|
(BYTE)iLevel,
|
||
|
SurfInfo[index].hKernelHandle);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This is driver kind of cube-map; could be driver managed
|
||
|
m_prgCubeSurfaces[index] =
|
||
|
new CDriverCubeSurface(this,
|
||
|
(BYTE)iFace,
|
||
|
(BYTE)iLevel,
|
||
|
SurfInfo[index].hKernelHandle);
|
||
|
}
|
||
|
|
||
|
if (m_prgCubeSurfaces[index] == NULL)
|
||
|
{
|
||
|
DPF_ERR("Out of memory creating cube map level");
|
||
|
*phr = E_OUTOFMEMORY;
|
||
|
|
||
|
// Need to free handles that we got before we return; we
|
||
|
// only free the ones that weren't successfully entrusted
|
||
|
// to a CCubeSurf because those will be cleaned up automatically
|
||
|
// at their destructor
|
||
|
if (UserPool != D3DPOOL_SCRATCH)
|
||
|
{
|
||
|
for (UINT i = index; i < ((cFaces * cLevels) - 1); i++)
|
||
|
{
|
||
|
DXGASSERT(SurfInfo[i].hKernelHandle);
|
||
|
|
||
|
D3D8_DESTROYSURFACEDATA DestroySurfData;
|
||
|
DestroySurfData.hDD = Device()->GetHandle();
|
||
|
DestroySurfData.hSurface = SurfInfo[i].hKernelHandle;
|
||
|
Device()->GetHalCallbacks()->DestroySurface(&DestroySurfData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If this is a D3D managed surface then we need
|
||
|
// to tell the Resource Manager to remember us. This has to happen
|
||
|
// at the very end of the constructor so that the important data
|
||
|
// members are built up correctly
|
||
|
if (CResource::IsTypeD3DManaged(Device(), D3DRTYPE_CUBETEXTURE, UserPool))
|
||
|
{
|
||
|
*phr = InitializeRMHandle();
|
||
|
}
|
||
|
|
||
|
} // CCubeMap::CCubeMap
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::~CCubeMap"
|
||
|
|
||
|
// Destructor
|
||
|
CCubeMap::~CCubeMap()
|
||
|
{
|
||
|
// The destructor has to handle partially
|
||
|
// created objects.
|
||
|
|
||
|
if (m_prgCubeSurfaces)
|
||
|
{
|
||
|
// How many faces do we have?
|
||
|
DWORD cFaces = 6;
|
||
|
|
||
|
// Delete each CubeSurface individually
|
||
|
for (DWORD iSurf = 0; iSurf < (cFaces * m_cLevels); iSurf++)
|
||
|
{
|
||
|
delete m_prgCubeSurfaces[iSurf];
|
||
|
}
|
||
|
delete [] m_prgCubeSurfaces;
|
||
|
}
|
||
|
delete [] m_rgbPixels;
|
||
|
} // CCubeMap::~CCubeMap
|
||
|
|
||
|
// Methods for the Resource Manager
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::Clone"
|
||
|
|
||
|
// Specifies a creation of a resource that
|
||
|
// looks just like the current one; in a new POOL
|
||
|
// with a new LOD.
|
||
|
HRESULT CCubeMap::Clone(D3DPOOL Pool,
|
||
|
CResource **ppResource) const
|
||
|
|
||
|
{
|
||
|
// NULL out parameter
|
||
|
*ppResource = NULL;
|
||
|
|
||
|
// Determine the number of levels/width/height
|
||
|
// of the clone
|
||
|
DWORD cLevels = GetLevelCountImpl();
|
||
|
DWORD Edge = m_desc.Width;
|
||
|
DXGASSERT(m_desc.Width == m_desc.Height);
|
||
|
|
||
|
DWORD dwLOD = GetLODI();
|
||
|
|
||
|
// If LOD is zero, then there are no changes
|
||
|
if (dwLOD > 0)
|
||
|
{
|
||
|
// Clamp LOD to cLevels-1
|
||
|
if (dwLOD >= cLevels)
|
||
|
{
|
||
|
dwLOD = cLevels - 1;
|
||
|
}
|
||
|
|
||
|
// scale down the destination texture
|
||
|
// to correspond the appropiate max lod
|
||
|
Edge >>= dwLOD;
|
||
|
if (Edge == 0)
|
||
|
Edge = 1;
|
||
|
|
||
|
// Reduce the number based on the our max lod.
|
||
|
cLevels -= dwLOD;
|
||
|
}
|
||
|
|
||
|
// Sanity checking
|
||
|
DXGASSERT(cLevels >= 1);
|
||
|
DXGASSERT(Edge > 0);
|
||
|
|
||
|
// Create the new cube-map object now
|
||
|
|
||
|
// Note: we treat clones as REF_INTERNAL; because
|
||
|
// they are owned by the resource manager which
|
||
|
// is owned by the device.
|
||
|
|
||
|
// Also, we adjust the usage to disable lock-flags
|
||
|
// since we don't need lockability
|
||
|
DWORD Usage = m_desc.Usage;
|
||
|
Usage &= ~(D3DUSAGE_LOCK | D3DUSAGE_LOADONCE);
|
||
|
|
||
|
HRESULT hr;
|
||
|
CResource *pResource = new CCubeMap(Device(),
|
||
|
Edge,
|
||
|
cLevels,
|
||
|
Usage,
|
||
|
m_desc.Format, // UserFormat
|
||
|
m_desc.Format, // RealFormat
|
||
|
Pool,
|
||
|
REF_INTERNAL,
|
||
|
&hr);
|
||
|
|
||
|
if (pResource == NULL)
|
||
|
{
|
||
|
DPF_ERR("Failed to allocate cube-map object when copying");
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPF(5, "Failed to create cube-map when doing texture management");
|
||
|
pResource->DecrementUseCount();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*ppResource = pResource;
|
||
|
|
||
|
return hr;
|
||
|
} // CCubeMap::Clone
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetBufferDesc"
|
||
|
|
||
|
// Provides a method to access basic structure of the
|
||
|
// pieces of the resource. A resource may be composed
|
||
|
// of one or more buffers.
|
||
|
const D3DBUFFER_DESC* CCubeMap::GetBufferDesc() const
|
||
|
{
|
||
|
return (const D3DBUFFER_DESC*)&m_desc;
|
||
|
} // CCubeMap::GetBufferDesc
|
||
|
|
||
|
|
||
|
// IUnknown methods
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::QueryInterface"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::QueryInterface(REFIID riid,
|
||
|
LPVOID FAR * ppvObj)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
if (!VALID_PTR_PTR(ppvObj))
|
||
|
{
|
||
|
DPF_ERR("Invalid ppvObj parameter to QueryInterface for Cubemap");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (!VALID_PTR(&riid, sizeof(GUID)))
|
||
|
{
|
||
|
DPF_ERR("Invalid guid memory address to QueryInterface for Cubemap");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (riid == IID_IDirect3DCubeTexture8 ||
|
||
|
riid == IID_IDirect3DBaseTexture8 ||
|
||
|
riid == IID_IDirect3DResource8 ||
|
||
|
riid == IID_IUnknown)
|
||
|
{
|
||
|
*ppvObj = static_cast<void*>(static_cast<IDirect3DCubeTexture8*>(this));
|
||
|
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
DPF_ERR("Unsupported Interface identifier passed to QueryInterface for Cubemap");
|
||
|
|
||
|
// Null out param
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
} // QueryInterface
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::AddRef"
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CCubeMap::AddRef()
|
||
|
{
|
||
|
API_ENTER_NO_LOCK(Device());
|
||
|
|
||
|
return AddRefImpl();
|
||
|
} // AddRef
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::Release"
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CCubeMap::Release()
|
||
|
{
|
||
|
API_ENTER_SUBOBJECT_RELEASE(Device());
|
||
|
|
||
|
return ReleaseImpl();
|
||
|
} // Release
|
||
|
|
||
|
// IDirect3DResource methods
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetDevice"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::GetDevice(IDirect3DDevice8 ** ppvObj)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
return GetDeviceImpl(ppvObj);
|
||
|
} // GetDevice
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::SetPrivateData"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::SetPrivateData(REFGUID riid,
|
||
|
CONST VOID* pvData,
|
||
|
DWORD cbData,
|
||
|
DWORD dwFlags)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
// For the private data that 'really' belongs to the
|
||
|
// CubeMap, we use m_cLevels. (0 through m_cLevels-1 are for
|
||
|
// each of the children levels.)
|
||
|
|
||
|
return SetPrivateDataImpl(riid, pvData, cbData, dwFlags, m_cLevels);
|
||
|
} // SetPrivateData
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetPrivateData"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::GetPrivateData(REFGUID riid,
|
||
|
LPVOID pvData,
|
||
|
LPDWORD pcbData)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
// For the private data that 'really' belongs to the
|
||
|
// CubeMap, we use m_cLevels. (0 through m_cLevels-1 are for
|
||
|
// each of the children levels.)
|
||
|
return GetPrivateDataImpl(riid, pvData, pcbData, m_cLevels);
|
||
|
} // GetPrivateData
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::FreePrivateData"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::FreePrivateData(REFGUID riid)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
// For the private data that 'really' belongs to the
|
||
|
// CubeMap, we use m_cLevels. (0 through m_cLevels-1 are for
|
||
|
// each of the children levels.)
|
||
|
return FreePrivateDataImpl(riid, m_cLevels);
|
||
|
} // FreePrivateData
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetPriority"
|
||
|
|
||
|
STDMETHODIMP_(DWORD) CCubeMap::GetPriority()
|
||
|
{
|
||
|
API_ENTER_RET(Device(), DWORD);
|
||
|
|
||
|
return GetPriorityImpl();
|
||
|
} // GetPriority
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::SetPriority"
|
||
|
|
||
|
STDMETHODIMP_(DWORD) CCubeMap::SetPriority(DWORD dwPriority)
|
||
|
{
|
||
|
API_ENTER_RET(Device(), DWORD);
|
||
|
|
||
|
return SetPriorityImpl(dwPriority);
|
||
|
} // SetPriority
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::PreLoad"
|
||
|
|
||
|
STDMETHODIMP_(void) CCubeMap::PreLoad(void)
|
||
|
{
|
||
|
API_ENTER_VOID(Device());
|
||
|
|
||
|
PreLoadImpl();
|
||
|
return;
|
||
|
} // PreLoad
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetType"
|
||
|
STDMETHODIMP_(D3DRESOURCETYPE) CCubeMap::GetType(void)
|
||
|
{
|
||
|
API_ENTER_RET(Device(), D3DRESOURCETYPE);
|
||
|
|
||
|
return m_desc.Type;
|
||
|
} // GetType
|
||
|
|
||
|
|
||
|
// IDirect3DMipTexture methods
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetLOD"
|
||
|
|
||
|
STDMETHODIMP_(DWORD) CCubeMap::GetLOD()
|
||
|
{
|
||
|
API_ENTER_RET(Device(), DWORD);
|
||
|
|
||
|
return GetLODImpl();
|
||
|
} // GetLOD
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::SetLOD"
|
||
|
|
||
|
STDMETHODIMP_(DWORD) CCubeMap::SetLOD(DWORD dwLOD)
|
||
|
{
|
||
|
API_ENTER_RET(Device(), DWORD);
|
||
|
|
||
|
return SetLODImpl(dwLOD);
|
||
|
} // SetLOD
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetLevelCount"
|
||
|
|
||
|
STDMETHODIMP_(DWORD) CCubeMap::GetLevelCount()
|
||
|
{
|
||
|
API_ENTER_RET(Device(), DWORD);
|
||
|
|
||
|
return GetLevelCountImpl();
|
||
|
} // GetLevelCount
|
||
|
|
||
|
|
||
|
// IDirect3DCubeMap methods
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetLevelDesc"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::GetLevelDesc(UINT iLevel, D3DSURFACE_DESC *pDesc)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
if (iLevel >= m_cLevels)
|
||
|
{
|
||
|
DPF_ERR("Invalid level number passed CCubeMap::GetLevelDesc");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
D3DCUBEMAP_FACES FaceType = D3DCUBEMAP_FACE_POSITIVE_X;
|
||
|
|
||
|
return GetSurface(FaceType, iLevel)->GetDesc(pDesc);
|
||
|
|
||
|
} // GetLevelDesc
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::GetCubeMapSurface"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::GetCubeMapSurface(D3DCUBEMAP_FACES FaceType,
|
||
|
UINT iLevel,
|
||
|
IDirect3DSurface8 **ppSurface)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
if (!VALID_PTR_PTR(ppSurface))
|
||
|
{
|
||
|
DPF_ERR("Invalid ppSurface parameter passed to CCubeMap::GetCubeMapSurface");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Null out parameter
|
||
|
*ppSurface = NULL;
|
||
|
|
||
|
// Continue parameter checking
|
||
|
if (iLevel >= m_cLevels)
|
||
|
{
|
||
|
DPF_ERR("Invalid level number passed CCubeMap::OpenCubemapLevel");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
if (!VALID_CUBEMAP_FACETYPE(FaceType))
|
||
|
{
|
||
|
DPF_ERR("Invalid face type passed CCubeMap::OpenCubemapLevel");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
// Count bits in dwAllFaces less than dwFaceType's bit
|
||
|
*ppSurface = GetSurface(FaceType, iLevel);
|
||
|
(*ppSurface)->AddRef();
|
||
|
return S_OK;
|
||
|
} // GetCubeMapSurface
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::LockRect"
|
||
|
STDMETHODIMP CCubeMap::LockRect(D3DCUBEMAP_FACES FaceType,
|
||
|
UINT iLevel,
|
||
|
D3DLOCKED_RECT *pLockedRectData,
|
||
|
CONST RECT *pRect,
|
||
|
DWORD dwFlags)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
if (pLockedRectData == NULL)
|
||
|
{
|
||
|
DPF_ERR("Invalid parameter passed to CCubeMap::LockRect");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (!VALID_CUBEMAP_FACETYPE(FaceType))
|
||
|
{
|
||
|
DPF_ERR("Invalid face type passed CCubeMap::LockRect");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (iLevel >= m_cLevels)
|
||
|
{
|
||
|
DPF_ERR("Invalid level number passed CCubeMap::LockRect");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
return GetSurface(FaceType, iLevel)->LockRect(pLockedRectData, pRect, dwFlags);
|
||
|
} // LockRect
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::UnlockRect"
|
||
|
|
||
|
STDMETHODIMP CCubeMap::UnlockRect(D3DCUBEMAP_FACES FaceType, UINT iLevel)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
if (!VALID_CUBEMAP_FACETYPE(FaceType))
|
||
|
{
|
||
|
DPF_ERR("Invalid face type passed CCubeMap::UnlockRect");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
if (iLevel >= m_cLevels)
|
||
|
{
|
||
|
DPF_ERR("Invalid level number passed CCubeMap::UnlockRect");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
return GetSurface(FaceType, iLevel)->UnlockRect();
|
||
|
|
||
|
} // UnlockRect
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::UpdateTexture"
|
||
|
|
||
|
// This function does type-specific parameter checking
|
||
|
// before calling UpdateDirtyPortion
|
||
|
HRESULT CCubeMap::UpdateTexture(CBaseTexture *pResourceTarget)
|
||
|
{
|
||
|
CCubeMap *pTexSource = static_cast<CCubeMap*>(this);
|
||
|
CCubeMap *pTexDest = static_cast<CCubeMap*>(pResourceTarget);
|
||
|
|
||
|
// Figure out how many levels in the source to skip
|
||
|
DXGASSERT(pTexSource->m_cLevels >= pTexDest->m_cLevels);
|
||
|
DWORD StartLevel = pTexSource->m_cLevels - pTexDest->m_cLevels;
|
||
|
DXGASSERT(StartLevel < 32);
|
||
|
|
||
|
// Compute the size of the top level of the source that is
|
||
|
// going to be copied.
|
||
|
UINT SrcWidth = pTexSource->Desc()->Width;
|
||
|
UINT SrcHeight = pTexSource->Desc()->Height;
|
||
|
if (StartLevel > 0)
|
||
|
{
|
||
|
SrcWidth >>= StartLevel;
|
||
|
SrcHeight >>= StartLevel;
|
||
|
if (SrcWidth == 0)
|
||
|
SrcWidth = 1;
|
||
|
if (SrcHeight == 0)
|
||
|
SrcHeight = 1;
|
||
|
}
|
||
|
|
||
|
// Source and Dest should be the same sizes at this point
|
||
|
if (SrcWidth != pTexDest->Desc()->Width)
|
||
|
{
|
||
|
if (StartLevel)
|
||
|
{
|
||
|
DPF_ERR("Source and Destination for UpdateTexture are not"
|
||
|
" compatible. Since both have the same number of"
|
||
|
" levels; their widths must match. UpdateTexture"
|
||
|
" for CubeTexture fails");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF_ERR("Source and Destination for UpdateTexture are not"
|
||
|
" compatible. Since they have the different numbers of"
|
||
|
" levels; the widths of the bottom-most levels of"
|
||
|
" the source must match all the corresponding levels"
|
||
|
" of the destination. UpdateTexture"
|
||
|
" for CubeTexture fails");
|
||
|
}
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (SrcHeight != pTexDest->Desc()->Height)
|
||
|
{
|
||
|
if (StartLevel)
|
||
|
{
|
||
|
DPF_ERR("Source and Destination for UpdateTexture are not"
|
||
|
" compatible. Since both have the same number of"
|
||
|
" levels; their heights must match. UpdateTexture"
|
||
|
" for CubeTexture fails");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF_ERR("Source and Destination for UpdateTexture are not"
|
||
|
" compatible. Since they have the different numbers of"
|
||
|
" mip-levels; the heights of the bottom-most levels of"
|
||
|
" the source must match all the corresponding levels"
|
||
|
" of the destination. UpdateTexture"
|
||
|
" for CubeTexture fails");
|
||
|
}
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
return UpdateDirtyPortion(pResourceTarget);
|
||
|
} // UpdateTexture
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::UpdateDirtyPortion"
|
||
|
|
||
|
// Tells the resource that it should copy itself
|
||
|
// to the target. It is the caller's responsibility
|
||
|
// to make sure that Target is compatible with the
|
||
|
// Source. (The Target may have different number of mip-levels
|
||
|
// and be in a different pool; however, it must have the same size,
|
||
|
// faces, format, etc.)
|
||
|
//
|
||
|
// This function will clear the dirty state.
|
||
|
HRESULT CCubeMap::UpdateDirtyPortion(CResource *pResourceTarget)
|
||
|
{
|
||
|
// If we are clean, then do nothing
|
||
|
if (!m_IsAnyFaceDirty)
|
||
|
{
|
||
|
if (IsDirty())
|
||
|
{
|
||
|
DPF_ERR("A Cube Texture has been locked with D3DLOCK_NO_DIRTY_UPDATE but "
|
||
|
"no call to AddDirtyRect was made before the texture was used. "
|
||
|
"Hardware texture was not updated.");
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// We are dirty; so we need to get some pointers
|
||
|
CCubeMap *pTexSource = static_cast<CCubeMap*>(this);
|
||
|
CCubeMap *pTexDest = static_cast<CCubeMap*>(pResourceTarget);
|
||
|
|
||
|
// Call TexBlt for each face
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (CanTexBlt(pTexDest))
|
||
|
{
|
||
|
CD3DBase *pDevice = static_cast<CD3DBase*>(Device());
|
||
|
|
||
|
// Hack: go in reverse order for driver compat.
|
||
|
for (INT iFace = CUBEMAP_MAXFACES-1;
|
||
|
iFace >= 0;
|
||
|
iFace--)
|
||
|
{
|
||
|
// Skip clean faces
|
||
|
if (m_IsFaceCleanArray[iFace])
|
||
|
continue;
|
||
|
|
||
|
// Figure out the right handles to use for this operation
|
||
|
D3DCUBEMAP_FACES Face = (D3DCUBEMAP_FACES) iFace;
|
||
|
DWORD dwDest = pTexDest->GetSurface(Face, 0 /* iLevel */)->DrawPrimHandle();
|
||
|
DWORD dwSource = pTexSource->GetSurface(Face, 0 /* iLevel */)->DrawPrimHandle();
|
||
|
|
||
|
// Is this face all dirty?
|
||
|
if (m_IsFaceAllDirtyArray[iFace])
|
||
|
{
|
||
|
POINT p = {0 , 0};
|
||
|
RECTL r = {0, 0, Desc()->Width, Desc()->Height};
|
||
|
|
||
|
hr = pDevice->CubeTexBlt(pTexDest,
|
||
|
pTexSource,
|
||
|
dwDest,
|
||
|
dwSource,
|
||
|
&p,
|
||
|
&r);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// this face must be dirty
|
||
|
DXGASSERT(!m_IsFaceCleanArray[iFace]);
|
||
|
|
||
|
// Is this face partially dirty
|
||
|
hr = pDevice->CubeTexBlt(pTexDest,
|
||
|
pTexSource,
|
||
|
dwDest,
|
||
|
dwSource,
|
||
|
(LPPOINT)&m_DirtyRectArray[iFace],
|
||
|
(LPRECTL)&m_DirtyRectArray[iFace]);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPF_ERR("Failed to update texture; not clearing dirty state for Cubemap");
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We can't use TexBlt, so we have to copy each level individually
|
||
|
// through InternalCopyRects
|
||
|
|
||
|
// Determine number of source levels to skip
|
||
|
DXGASSERT(pTexSource->m_cLevels >= pTexDest->m_cLevels);
|
||
|
DWORD StartLevel = pTexSource->m_cLevels - pTexDest->m_cLevels;
|
||
|
DWORD LevelsToCopy = pTexSource->m_cLevels - StartLevel;
|
||
|
DXGASSERT(StartLevel < this->m_cLevels);
|
||
|
DXGASSERT(0 < pTexDest->m_cLevels);
|
||
|
|
||
|
CBaseSurface *pSurfaceSrc;
|
||
|
CBaseSurface *pSurfaceDest;
|
||
|
|
||
|
// Iterate over each face
|
||
|
for (DWORD iFace = 0; iFace < 6; iFace++)
|
||
|
{
|
||
|
if (m_IsFaceCleanArray[iFace])
|
||
|
continue;
|
||
|
|
||
|
if (m_IsFaceAllDirtyArray[iFace])
|
||
|
{
|
||
|
for (DWORD iLevel = 0; iLevel < LevelsToCopy; iLevel++)
|
||
|
{
|
||
|
DWORD IndexSrc = iFace * this->m_cLevels + iLevel + StartLevel;
|
||
|
DXGASSERT(IndexSrc < (DWORD)(this->m_cLevels * 6));
|
||
|
pSurfaceSrc = this->m_prgCubeSurfaces[IndexSrc];
|
||
|
|
||
|
DWORD IndexDest = iFace * pTexDest->m_cLevels + iLevel;
|
||
|
DXGASSERT(IndexDest < (DWORD)(pTexDest->m_cLevels * 6));
|
||
|
pSurfaceDest = pTexDest->m_prgCubeSurfaces[IndexDest];
|
||
|
|
||
|
// Source and Dest should be the same
|
||
|
// or our caller made a mistake
|
||
|
DXGASSERT(pSurfaceSrc->InternalGetDesc().Width ==
|
||
|
pSurfaceDest->InternalGetDesc().Width);
|
||
|
DXGASSERT(pSurfaceSrc->InternalGetDesc().Height ==
|
||
|
pSurfaceDest->InternalGetDesc().Height);
|
||
|
|
||
|
// Copy the entire level
|
||
|
hr = Device()->InternalCopyRects(pSurfaceSrc,
|
||
|
NULL,
|
||
|
0,
|
||
|
pSurfaceDest,
|
||
|
NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPF_ERR("Failed to update texture; not clearing dirty state for Cubemap");
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (StartLevel)
|
||
|
{
|
||
|
ScaleRectDown(&m_DirtyRectArray[iFace], StartLevel);
|
||
|
}
|
||
|
|
||
|
// Use the rect for the top level; but just
|
||
|
// copy the entirety of other levels
|
||
|
DWORD iLevel = 0;
|
||
|
|
||
|
DWORD IndexSrc = iFace * this->m_cLevels + iLevel + StartLevel;
|
||
|
DXGASSERT(IndexSrc < (DWORD)(this->m_cLevels * 6));
|
||
|
pSurfaceSrc = this->m_prgCubeSurfaces[IndexSrc];
|
||
|
|
||
|
DWORD IndexDest = iFace * pTexDest->m_cLevels + iLevel;
|
||
|
DXGASSERT(IndexDest < (DWORD)(pTexDest->m_cLevels * 6));
|
||
|
pSurfaceDest = pTexDest->m_prgCubeSurfaces[IndexDest];
|
||
|
|
||
|
|
||
|
DXGASSERT(pSurfaceSrc->InternalGetDesc().Width ==
|
||
|
pSurfaceDest->InternalGetDesc().Width);
|
||
|
DXGASSERT(pSurfaceSrc->InternalGetDesc().Height ==
|
||
|
pSurfaceDest->InternalGetDesc().Height);
|
||
|
|
||
|
// Passing pPoints as NULL means just do a non-translated
|
||
|
// copy
|
||
|
hr = Device()->InternalCopyRects(pSurfaceSrc,
|
||
|
&m_DirtyRectArray[iFace],
|
||
|
1,
|
||
|
pSurfaceDest,
|
||
|
NULL); // pPoints
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPF_ERR("Failed to update texture; not clearing dirty state for Cubemap");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Copy each of the levels
|
||
|
for (iLevel = 1; iLevel < LevelsToCopy; iLevel++)
|
||
|
{
|
||
|
// Get the next surfaces
|
||
|
DWORD IndexSrc = iFace * this->m_cLevels + iLevel + StartLevel;
|
||
|
DXGASSERT(IndexSrc < (DWORD)(this->m_cLevels * 6));
|
||
|
pSurfaceSrc = this->m_prgCubeSurfaces[IndexSrc];
|
||
|
|
||
|
DWORD IndexDest = iFace * pTexDest->m_cLevels + iLevel;
|
||
|
DXGASSERT(IndexDest < (DWORD)(pTexDest->m_cLevels * 6));
|
||
|
pSurfaceDest = pTexDest->m_prgCubeSurfaces[IndexDest];
|
||
|
|
||
|
// Check that sizes match
|
||
|
DXGASSERT(pSurfaceSrc->InternalGetDesc().Width ==
|
||
|
pSurfaceDest->InternalGetDesc().Width);
|
||
|
DXGASSERT(pSurfaceSrc->InternalGetDesc().Height ==
|
||
|
pSurfaceDest->InternalGetDesc().Height);
|
||
|
|
||
|
// Copy the entirety of non-top levels
|
||
|
hr = Device()->InternalCopyRects(pSurfaceSrc,
|
||
|
NULL,
|
||
|
0,
|
||
|
pSurfaceDest,
|
||
|
NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPF_ERR("Failed to update texture; not clearing dirty state for Cubemap");
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remember that we did the work
|
||
|
m_IsAnyFaceDirty = FALSE;
|
||
|
for (DWORD iFace = 0; iFace < CUBEMAP_MAXFACES; iFace++)
|
||
|
{
|
||
|
m_IsFaceCleanArray [iFace] = TRUE;
|
||
|
m_IsFaceAllDirtyArray[iFace] = FALSE;
|
||
|
}
|
||
|
|
||
|
// Notify Resource base class that we are now clean
|
||
|
OnResourceClean();
|
||
|
DXGASSERT(!IsDirty());
|
||
|
|
||
|
return S_OK;
|
||
|
} // CCubeMap::UpdateDirtyPortion
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::MarkAllDirty"
|
||
|
|
||
|
// Allows the Resource Manager to mark the texture
|
||
|
// as needing to be completely updated on next
|
||
|
// call to UpdateDirtyPortion
|
||
|
void CCubeMap::MarkAllDirty()
|
||
|
{
|
||
|
// Set palette to __INVALIDPALETTE so that UpdateTextures
|
||
|
// calls the DDI SetPalette the next time.
|
||
|
SetPalette(__INVALIDPALETTE);
|
||
|
|
||
|
// Mark everything dirty
|
||
|
m_IsAnyFaceDirty = TRUE;
|
||
|
for (int iFace = 0; iFace < CUBEMAP_MAXFACES; iFace++)
|
||
|
{
|
||
|
m_IsFaceCleanArray [iFace] = FALSE;
|
||
|
m_IsFaceAllDirtyArray[iFace] = TRUE;
|
||
|
}
|
||
|
|
||
|
// Notify Resource base class that we are now dirty
|
||
|
OnResourceDirty();
|
||
|
|
||
|
} // CCubeMap::MarkAllDirty
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::AddDirtyRect"
|
||
|
STDMETHODIMP CCubeMap::AddDirtyRect(D3DCUBEMAP_FACES FaceType,
|
||
|
CONST RECT *pRect)
|
||
|
{
|
||
|
API_ENTER(Device());
|
||
|
|
||
|
if (pRect != NULL && !VALID_PTR(pRect, sizeof(RECT)))
|
||
|
{
|
||
|
DPF_ERR("Invalid Rect parameter to AddDirtyRect for Cubemap");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (!VALID_CUBEMAP_FACETYPE(FaceType))
|
||
|
{
|
||
|
DPF_ERR("Invalid FaceType parameter to AddDirtyRect for Cubemap");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
if (pRect)
|
||
|
{
|
||
|
if (!CPixel::IsValidRect(Desc()->Format,
|
||
|
Desc()->Width,
|
||
|
Desc()->Height,
|
||
|
pRect))
|
||
|
{
|
||
|
DPF_ERR("AddDirtyRect for a Cube Texture failed");
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
InternalAddDirtyRect((UINT)FaceType, pRect);
|
||
|
return S_OK;
|
||
|
} // AddDirtyRect
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::InternalAddDirtyRect"
|
||
|
void CCubeMap::InternalAddDirtyRect(DWORD iFace,
|
||
|
CONST RECT *pRect)
|
||
|
{
|
||
|
// If driver managed then batch token
|
||
|
if (Desc()->Pool == D3DPOOL_MANAGED && !IsD3DManaged())
|
||
|
{
|
||
|
RECTL Rect;
|
||
|
DXGASSERT((Device()->GetD3DCaps()->Caps2 & DDCAPS2_CANMANAGERESOURCE) != 0);
|
||
|
if (pRect == NULL)
|
||
|
{
|
||
|
Rect.left = 0;
|
||
|
Rect.top = 0;
|
||
|
Rect.right = (LONG)Desc()->Width;
|
||
|
Rect.bottom = (LONG)Desc()->Height;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Rect = *((CONST RECTL*)pRect);
|
||
|
}
|
||
|
static_cast<CD3DBase*>(Device())->AddCubeDirtyRect(this,
|
||
|
GetSurface((D3DCUBEMAP_FACES)iFace, 0)->DrawPrimHandle(),
|
||
|
&Rect); // This will fail only due to catastrophic
|
||
|
// error and we or the app can't do a
|
||
|
// a whole lot about it, so return nothing
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Need to mark dirty bit in CResource so that the resource manager works correctly.
|
||
|
OnResourceDirty();
|
||
|
|
||
|
// If everything is being modified; then we're totally dirty
|
||
|
if (pRect == NULL)
|
||
|
{
|
||
|
m_IsFaceAllDirtyArray[iFace] = TRUE;
|
||
|
m_IsFaceCleanArray [iFace] = FALSE;
|
||
|
m_IsAnyFaceDirty = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If we're all dirty, we can't get dirtier
|
||
|
if (m_IsFaceAllDirtyArray[iFace])
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If the rect is the entire surface then we're all dirty
|
||
|
DXGASSERT(pRect != NULL);
|
||
|
if (pRect->left == 0 &&
|
||
|
pRect->top == 0 &&
|
||
|
pRect->right == (LONG)Desc()->Width &&
|
||
|
pRect->bottom == (LONG)Desc()->Height)
|
||
|
{
|
||
|
m_IsFaceAllDirtyArray[iFace] = TRUE;
|
||
|
m_IsFaceCleanArray [iFace] = FALSE;
|
||
|
m_IsAnyFaceDirty = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If the face is currently clean; then just remember the
|
||
|
// new rect
|
||
|
if (m_IsFaceCleanArray[iFace])
|
||
|
{
|
||
|
m_DirtyRectArray [iFace] = *pRect;
|
||
|
m_IsFaceCleanArray[iFace] = FALSE;
|
||
|
m_IsAnyFaceDirty = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Union in this Rect
|
||
|
|
||
|
// If we're unioning in rects, then we must
|
||
|
// already be marked dirty but not all dirty
|
||
|
DXGASSERT(!m_IsFaceAllDirtyArray[iFace]);
|
||
|
DXGASSERT(m_IsAnyFaceDirty);
|
||
|
|
||
|
if (m_DirtyRectArray[iFace].left > pRect->left)
|
||
|
{
|
||
|
m_DirtyRectArray[iFace].left = pRect->left;
|
||
|
}
|
||
|
if (m_DirtyRectArray[iFace].right < pRect->right)
|
||
|
{
|
||
|
m_DirtyRectArray[iFace].right = pRect->right;
|
||
|
}
|
||
|
if (m_DirtyRectArray[iFace].top > pRect->top)
|
||
|
{
|
||
|
m_DirtyRectArray[iFace].top = pRect->top;
|
||
|
}
|
||
|
if (m_DirtyRectArray[iFace].bottom < pRect->bottom)
|
||
|
{
|
||
|
m_DirtyRectArray[iFace].bottom = pRect->bottom;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
} // InternalAddDirtyRect
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::OnSurfaceLock"
|
||
|
|
||
|
// Methods for the CubeSurface to call
|
||
|
// Notification when a cube-surface is locked for writing
|
||
|
void CCubeMap::OnSurfaceLock(DWORD iFace,
|
||
|
DWORD iLevel,
|
||
|
CONST RECT *pRect,
|
||
|
DWORD dwFlags)
|
||
|
{
|
||
|
// Need to Sync first
|
||
|
Sync();
|
||
|
|
||
|
// We only care about the top-most levels of the cube-map
|
||
|
if (iLevel != 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// We don't need to mark the surface dirty if this was a
|
||
|
// read-only lock; (this can happen for RT+Tex where we
|
||
|
// need to sync even for read-only locks).
|
||
|
if (dwFlags & D3DLOCK_READONLY)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Notify the resource that we are dirty
|
||
|
OnResourceDirty();
|
||
|
|
||
|
// Don't do anything if we are already all dirty or
|
||
|
// if the app has specified that we shouldn't keep
|
||
|
// track of this rect
|
||
|
if (!m_IsFaceAllDirtyArray[iFace] &&
|
||
|
!(dwFlags & D3DLOCK_NO_DIRTY_UPDATE))
|
||
|
{
|
||
|
InternalAddDirtyRect(iFace, pRect);
|
||
|
}
|
||
|
// We're done now.
|
||
|
return;
|
||
|
|
||
|
} // OnSurfaceLock
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CCubeMap::IsTextureLocked"
|
||
|
|
||
|
// Debug only parameter checking do determine if a piece
|
||
|
// of a mip-chain is locked
|
||
|
#ifdef DEBUG
|
||
|
BOOL CCubeMap::IsTextureLocked()
|
||
|
{
|
||
|
for (DWORD iFace = 0; iFace < 6; iFace++)
|
||
|
{
|
||
|
for (UINT iLevel = 0; iLevel < m_cLevels; iLevel++)
|
||
|
{
|
||
|
D3DCUBEMAP_FACES Face = (D3DCUBEMAP_FACES) iFace;
|
||
|
if (GetSurface(Face, iLevel)->IsLocked())
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
|
||
|
} // IsTextureLocked
|
||
|
#endif // !DEBUG
|
||
|
|
||
|
|
||
|
// End of file : cubemap.cpp
|