windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/fw/surface.cpp

1029 lines
29 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*==========================================================================;
*
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
*
* File: surface.cpp
* Content: Implementation of the CSurface class.
*
*
***************************************************************************/
#include "ddrawpr.h"
#include "surface.hpp"
#include "pixel.hpp"
#include "swapchan.hpp"
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::Create"
// Static class function for creating a RenderTarget/ZStencil object.
// (Because it is static; it doesn't have a this pointer.)
HRESULT CSurface::Create(CBaseDevice *pDevice,
DWORD Width,
DWORD Height,
DWORD Usage,
D3DFORMAT UserFormat,
D3DMULTISAMPLE_TYPE MultiSampleType,
REF_TYPE refType,
IDirect3DSurface8 **ppSurface)
{
HRESULT hr;
// Do parameter checking here
if (!VALID_PTR_PTR(ppSurface))
{
DPF_ERR("Bad parameter passed for ppSurface for creating a surface. CreateRenderTarget/CreateDepthStencil failed");
return D3DERR_INVALIDCALL;
}
// Zero-out return parameter
*ppSurface = NULL;
// Size may need to be 4x4
if (CPixel::Requires4X4(UserFormat))
{
if ((Width & 3) ||
(Height & 3))
{
DPF_ERR("DXT Formats require width/height to be a multiple of 4. CreateRenderTarget/CreateDepthStencil failed.");
return D3DERR_INVALIDCALL;
}
}
// Validate against zero width/height
if (Width == 0 ||
Height == 0)
{
DPF_ERR("Width/Height must be non-zero. CreateRenderTarget/CreateDepthStencil failed");
return D3DERR_INVALIDCALL;
}
// Now verify that the device can support the specified format
hr = pDevice->CheckDeviceFormat(
Usage & (D3DUSAGE_RENDERTARGET |
D3DUSAGE_DEPTHSTENCIL),
D3DRTYPE_SURFACE,
UserFormat);
if (FAILED(hr))
{
DPF_ERR("The format is not supported by this device. CreateRenderTarget/CreateDepthStencil failed");
return D3DERR_INVALIDCALL;
}
// Infer lockability for DepthStencil from format
if (Usage & D3DUSAGE_DEPTHSTENCIL)
{
if (!CPixel::IsNonLockableZ(UserFormat))
{
Usage |= D3DUSAGE_LOCK;
}
}
// Validate lockability
if ((MultiSampleType != D3DMULTISAMPLE_NONE) &&
(Usage & D3DUSAGE_LOCK))
{
// RT have explicit lockability
if (Usage & D3DUSAGE_RENDERTARGET)
{
DPF_ERR("Multi-Sampled render-targets are not lockable. CreateRenderTarget failed");
return D3DERR_INVALIDCALL;
}
else
{
DPF_ERR("Multi-Sampled Depth Stencil buffers are not lockable. "
"Use D3DFMT_D16 instead of D3DFMT_D16_LOCKABLE. CreateDepthStencil failed");
return D3DERR_INVALIDCALL;
}
}
// Map depth/stencil format
D3DFORMAT RealFormat = pDevice->MapDepthStencilFormat(UserFormat);
// Create the surface
CSurface *pSurface;
pSurface = new CDriverSurface(pDevice,
Width,
Height,
Usage,
UserFormat,
RealFormat,
MultiSampleType,
0, // hKernelHandle
refType,
&hr);
if (pSurface == NULL)
{
DPF_ERR("Out of Memory creating surface. CreateRenderTarget/CreateDepthStencil failed");
return E_OUTOFMEMORY;
}
if (FAILED(hr))
{
DPF_ERR("Error during initialization of surface. CreateRenderTarget/CreateDepthStencil failed");
if (refType == REF_EXTERNAL)
{
// External objects get released
pSurface->Release();
}
else
{
// Internal and intrinsic objects get decremented
DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
pSurface->DecrementUseCount();
}
return hr;
}
// We're done; just return the object
*ppSurface = pSurface;
return hr;
} // static Create for ZBuffers and RenderTargets
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::CreateImageSurface"
// Function for creating sys-mem stand-alone surfaces
// that can be used with CopyRect and SetCursorSurface and
// ReadBuffer
HRESULT CSurface::CreateImageSurface(CBaseDevice *pDevice,
DWORD Width,
DWORD Height,
D3DFORMAT Format,
REF_TYPE refType,
IDirect3DSurface8 **ppSurface)
{
HRESULT hr;
// Do parameter checking here
if (!VALID_PTR_PTR(ppSurface))
{
DPF_ERR("Bad parameter passed for ppSurface for creating a surface. CreateImageSurface failed.");
return D3DERR_INVALIDCALL;
}
// Zero-out return parameter
*ppSurface = NULL;
// Has to be supported format
if (!CPixel::IsSupported(D3DRTYPE_SURFACE, Format))
{
DPF_ERR("This format is not supported for CreateImageSurface");
return D3DERR_INVALIDCALL;
}
if (CPixel::IsNonLockableZ(Format))
{
DPF_ERR("This Z format is not supported for CreateImageSurface");
return D3DERR_INVALIDCALL;
}
// Size may need to be 4x4
if (CPixel::Requires4X4(Format))
{
if ((Width & 3) ||
(Height & 3))
{
DPF_ERR("DXT Formats require width/height to be a multiple of 4. CreateImageSurface failed.");
return D3DERR_INVALIDCALL;
}
}
// Validate against zero width/height
if (Width == 0 ||
Height == 0)
{
DPF_ERR("Width/Height must be non-zero. CreateImageSurface failed.");
return D3DERR_INVALIDCALL;
}
// Usage is explictly just Usage_LOCK
DWORD Usage = D3DUSAGE_LOCK;
CSurface *pSurface = new CSysMemSurface(pDevice,
Width,
Height,
Usage,
Format,
refType,
&hr);
if (pSurface == NULL)
{
DPF_ERR("Out of Memory creating surface. CreateImageSurface failed.");
return E_OUTOFMEMORY;
}
if (FAILED(hr))
{
DPF_ERR("Error during initialization of surface. CreateImageSurface failed.");
if (refType == REF_EXTERNAL)
{
// External objects get released
pSurface->Release();
}
else
{
// Internal and intrinsic objects get decremented
DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
pSurface->DecrementUseCount();
}
return hr;
}
// We're done; just return the object
*ppSurface = pSurface;
return S_OK;
} // static CreateImageSurface
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::CSurface"
// Constructor the surface class; this is the
// base class for render targets/zbuffers/and backbuffers
CSurface::CSurface(CBaseDevice *pDevice,
DWORD Width,
DWORD Height,
DWORD Usage,
D3DFORMAT Format,
REF_TYPE refType,
HRESULT *phr
) :
CBaseObject(pDevice, refType),
m_qwBatchCount(0)
{
// Sanity check
DXGASSERT(phr);
// Initialize basic structures
m_desc.Format = Format;
m_desc.Pool = D3DPOOL_DEFAULT;
m_desc.Usage = Usage;
m_desc.Type = D3DRTYPE_SURFACE;
m_desc.Width = Width;
m_desc.Height = Height;
m_formatUser = Format;
m_poolUser = D3DPOOL_DEFAULT;
// Return success
*phr = S_OK;
} // CSurface::CSurface
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::~CSurface"
// Destructor
CSurface::~CSurface()
{
// The destructor has to handle partially
// created objects.
// Check to make sure that we aren't deleting
// an object that is referenced in the current (unflushed)
// command stream buffer.
DXGASSERT(m_qwBatchCount <= static_cast<CD3DBase*>(Device())->CurrentBatch());
} // CSurface::~CSurface
// IUnknown methods
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::QueryInterface"
STDMETHODIMP CSurface::QueryInterface(REFIID riid,
LPVOID FAR *ppvObj)
{
API_ENTER(Device());
if (!VALID_PTR_PTR(ppvObj))
{
DPF_ERR("Invalid ppvObj parameter passed to CSurface::QueryInterface");
return D3DERR_INVALIDCALL;
}
if (!VALID_PTR(&riid, sizeof(GUID)))
{
DPF_ERR("Invalid guid memory address to CSurface::QueryInterface");
return D3DERR_INVALIDCALL;
}
if (riid == IID_IDirect3DSurface8 || riid == IID_IUnknown)
{
*ppvObj = static_cast<void*>(static_cast<IDirect3DSurface8 *>(this));
AddRef();
return S_OK;
}
DPF_ERR("Unsupported Interface identifier passed to CSurface::QueryInterface");
// Null out param
*ppvObj = NULL;
return E_NOINTERFACE;
} // QueryInterface
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::AddRef"
STDMETHODIMP_(ULONG) CSurface::AddRef()
{
API_ENTER_NO_LOCK(Device());
return AddRefImpl();
} // AddRef
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::Release"
STDMETHODIMP_(ULONG) CSurface::Release()
{
API_ENTER_SUBOBJECT_RELEASE(Device());
return ReleaseImpl();
} // Release
// IDirect3DBuffer methods
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::GetDevice"
STDMETHODIMP CSurface::GetDevice(IDirect3DDevice8 ** ppObj)
{
API_ENTER(Device());
return GetDeviceImpl(ppObj);
} // GetDevice
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::SetPrivateData"
STDMETHODIMP CSurface::SetPrivateData(REFGUID riid,
CONST VOID* pvData,
DWORD cbData,
DWORD dwFlags)
{
API_ENTER(Device());
// We use level zero for our data
return SetPrivateDataImpl(riid, pvData, cbData, dwFlags, 0);
} // SetPrivateData
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::GetPrivateData"
STDMETHODIMP CSurface::GetPrivateData(REFGUID riid,
LPVOID pvData,
LPDWORD pcbData)
{
API_ENTER(Device());
// We use level zero for our data
return GetPrivateDataImpl(riid, pvData, pcbData, 0);
} // GetPrivateData
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::FreePrivateData"
STDMETHODIMP CSurface::FreePrivateData(REFGUID riid)
{
API_ENTER(Device());
// We use level zero for our data
return FreePrivateDataImpl(riid, 0);
} // FreePrivateData
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::GetContainer"
STDMETHODIMP CSurface::GetContainer(REFIID riid,
void **ppContainer)
{
API_ENTER(Device());
// Our 'container' is just the device since
// we are a standalone surface object
return Device()->QueryInterface( riid, ppContainer);
} // OpenContainer
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::GetDesc"
STDMETHODIMP CSurface::GetDesc(D3DSURFACE_DESC *pDesc)
{
API_ENTER(Device());
// If parameters are bad, then we should fail some stuff
if (!VALID_WRITEPTR(pDesc, sizeof(*pDesc)))
{
DPF_ERR("bad pointer for pDesc passed to CSurface::GetDesc");
return D3DERR_INVALIDCALL;
}
*pDesc = m_desc;
pDesc->Format = m_formatUser;
pDesc->Pool = m_poolUser;
pDesc->Usage &= D3DUSAGE_EXTERNAL;
return S_OK;
} // GetDesc
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::InternalGetDesc"
D3DSURFACE_DESC CSurface::InternalGetDesc() const
{
return m_desc;
} // InternalGetDesc
#ifdef DEBUG
#undef DPF_MODNAME
#define DPF_MODNAME "CSurface::ReportWhyLockFailed"
// DPF why Lock failed as clearly as possible
void CSurface::ReportWhyLockFailed(void) const
{
// If there are multiple reasons that lock failed; we report
// them all to minimize user confusion
if (InternalGetDesc().MultiSampleType != D3DMULTISAMPLE_NONE)
{
DPF_ERR("Lock is not supported for surfaces that have multi-sampling enabled.");
}
if (InternalGetDesc().Usage & D3DUSAGE_DEPTHSTENCIL)
{
DPF_ERR("Lock is not supported for depth formats other than D3DFMT_D16_LOCKABLE");
}
// If this is not a non-lockable Z format, and
// we are not multisampled; then the user must
// have explicitly chosen to create us in an non-lockable way
if (InternalGetDesc().Usage & D3DUSAGE_BACKBUFFER)
{
DPF_ERR("Backbuffers are not lockable unless application specifies "
"D3DPRESENTFLAG_LOCKABLE_BACKBUFFER at CreateDevice and Reset. "
"Lockable backbuffers incur a performance cost on some "
"graphics hardware.");
}
else if (InternalGetDesc().Usage & D3DUSAGE_RENDERTARGET)
{
DPF_ERR("RenderTargets are not lockable unless application specifies "
"TRUE for the Lockable parameter for CreateRenderTarget. Lockable "
"render targets incur a performance cost on some graphics hardware.");
}
// If we got here; then USAGE_LOCK should not have been set
DXGASSERT(!(InternalGetDesc().Usage & D3DUSAGE_LOCK));
return;
} // CSurface::ReportWhyLockFailed
#endif // DEBUG
//=============================================
// Methods for the CSysMemSurface class
//=============================================
#undef DPF_MODNAME
#define DPF_MODNAME "CSysMemSurface::CSysMemSurface"
CSysMemSurface::CSysMemSurface(CBaseDevice *pDevice,
DWORD Width,
DWORD Height,
DWORD Usage,
D3DFORMAT Format,
REF_TYPE refType,
HRESULT *phr
) :
CSurface(pDevice,
Width,
Height,
Usage,
Format,
refType,
phr),
m_rgbPixels(NULL)
{
if (FAILED(*phr))
return;
// Compute how much memory we need
m_desc.Size = CPixel::ComputeSurfaceSize(Width,
Height,
Format);
// Specify system memory
m_desc.Pool = D3DPOOL_SYSTEMMEM;
m_poolUser = D3DPOOL_SYSTEMMEM;
// Specify no multisampling
m_desc.MultiSampleType = D3DMULTISAMPLE_NONE;
// Allocate the memory
m_rgbPixels = new BYTE[m_desc.Size];
if (m_rgbPixels == NULL)
{
DPF_ERR("Out of memory allocating surface.");
*phr = E_OUTOFMEMORY;
return;
}
// Figure out our pitch
D3DLOCKED_RECT lock;
CPixel::ComputeSurfaceOffset(&m_desc,
m_rgbPixels,
NULL, // pRect
&lock);
// Create a DDSURFACE and CreateSurfaceData object
DDSURFACEINFO SurfInfo;
ZeroMemory(&SurfInfo, sizeof(SurfInfo));
// If we are not passed a handle, then we need to get one from
// the DDI
D3D8_CREATESURFACEDATA CreateSurfaceData;
ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
// Set up the basic information
CreateSurfaceData.hDD = pDevice->GetHandle();
CreateSurfaceData.pSList = &SurfInfo;
CreateSurfaceData.dwSCnt = 1;
// ImageSurface is an internal type so that the thunk layer
// knows that it is not really a texture
CreateSurfaceData.Type = D3DRTYPE_IMAGESURFACE;
CreateSurfaceData.Pool = m_desc.Pool;
CreateSurfaceData.dwUsage = m_desc.Usage;
CreateSurfaceData.MultiSampleType = D3DMULTISAMPLE_NONE;
CreateSurfaceData.Format = Format;
// Specify the surface data
SurfInfo.cpWidth = Width;
SurfInfo.cpHeight = Height;
SurfInfo.pbPixels = (BYTE*)lock.pBits;
SurfInfo.iPitch = lock.Pitch;
*phr = pDevice->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
if (FAILED(*phr))
{
DPF_ERR("Failed to create sys-mem surface");
return;
}
DXGASSERT(CreateSurfaceData.Pool == D3DPOOL_SYSTEMMEM);
DXGASSERT(m_desc.Pool == D3DPOOL_SYSTEMMEM);
DXGASSERT(m_poolUser == D3DPOOL_SYSTEMMEM);
SetKernelHandle(SurfInfo.hKernelHandle);
return;
} // CSysMemSurface::CSysMemSurface
#undef DPF_MODNAME
#define DPF_MODNAME "CSysMemSurface::~CSysMemSurface"
CSysMemSurface::~CSysMemSurface()
{
if (KernelHandle() != 0)
{
D3D8_DESTROYSURFACEDATA DestroyData;
ZeroMemory(&DestroyData, sizeof DestroyData);
DestroyData.hDD = Device()->GetHandle();
DestroyData.hSurface = KernelHandle();
Device()->GetHalCallbacks()->DestroySurface(&DestroyData);
}
// Free the memory we've allocated for the surface
delete [] m_rgbPixels;
return;
} // CSysMemSurface::CSysMemSurface
#undef DPF_MODNAME
#define DPF_MODNAME "CSysMemSurface::LockRect"
STDMETHODIMP CSysMemSurface::LockRect(D3DLOCKED_RECT *pLockedRectData,
CONST RECT *pRect,
DWORD dwFlags)
{
API_ENTER(Device());
// If parameters are bad, then we should fail some stuff
if (!VALID_WRITEPTR(pLockedRectData, sizeof(D3DLOCKED_RECT)))
{
DPF_ERR("bad pointer for m_pLockedRectData passed to LockRect for an ImageSurface.");
return D3DERR_INVALIDCALL;
}
// Zero out returned data
ZeroMemory(pLockedRectData, sizeof(D3DLOCKED_RECT));
// Validate Rect
if (pRect != NULL)
{
if (!CPixel::IsValidRect(m_desc.Format,
m_desc.Width,
m_desc.Height,
pRect))
{
DPF_ERR("LockRect for a Surface failed");
return D3DERR_INVALIDCALL;
}
}
if (dwFlags & ~D3DLOCK_SURF_VALID)
{
DPF_ERR("Invalid dwFlags parameter passed to LockRect for an ImageSurface");
DPF_EXPLAIN_BAD_LOCK_FLAGS(0, dwFlags & ~D3DLOCK_SURF_VALID);
return D3DERR_INVALIDCALL;
}
// Can't lock surfaces that are not lockable
if (!IsLockable())
{
ReportWhyLockFailed();
return D3DERR_INVALIDCALL;
}
return InternalLockRect(pLockedRectData, pRect, dwFlags);
} // LockRect
#undef DPF_MODNAME
#define DPF_MODNAME "CSysMemSurface::InternalLockRect"
HRESULT CSysMemSurface::InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
CONST RECT *pRect,
DWORD dwFlags)
{
// Only one lock outstanding at a time is supported
// (even internally)
if (m_isLocked)
{
DPF_ERR("LockRect failed on a surface; surface was already locked for an ImageSurface");
return D3DERR_INVALIDCALL;
}
CPixel::ComputeSurfaceOffset(&m_desc,
m_rgbPixels,
pRect,
pLockedRectData);
// Mark ourselves as locked
m_isLocked = TRUE;
// Done
return S_OK;
} // InternalLockRect
#undef DPF_MODNAME
#define DPF_MODNAME "CSysMemSurface::UnlockRect"
STDMETHODIMP CSysMemSurface::UnlockRect()
{
API_ENTER(Device());
// If we aren't locked; then something is wrong
if (!m_isLocked)
{
DPF_ERR("UnlockRect failed on a mip level; surface wasn't locked for an ImageSurface");
return D3DERR_INVALIDCALL;
}
DXGASSERT(IsLockable());
return InternalUnlockRect();
} // UnlockRect
#undef DPF_MODNAME
#define DPF_MODNAME "CSysMemSurface::InternalUnlockRect"
HRESULT CSysMemSurface::InternalUnlockRect()
{
DXGASSERT(m_isLocked);
// Clear our locked state
m_isLocked = FALSE;
// Done
return S_OK;
} // InternalUnlockRect
//=============================================
// Methods for the CDriverSurface class
//=============================================
#undef DPF_MODNAME
#define DPF_MODNAME "CDriverSurface::CDriverSurface"
CDriverSurface::CDriverSurface(CBaseDevice *pDevice,
DWORD Width,
DWORD Height,
DWORD Usage,
D3DFORMAT UserFormat,
D3DFORMAT RealFormat,
D3DMULTISAMPLE_TYPE MultiSampleType,
HANDLE hKernelHandle,
REF_TYPE refType,
HRESULT *phr
) :
CSurface(pDevice,
Width,
Height,
Usage,
RealFormat,
refType,
phr)
{
// Even in failure paths, we need to remember
// the passed in kernel handle so we can uniformly
// free it
if (hKernelHandle)
SetKernelHandle(hKernelHandle);
// On failure; just return here
if (FAILED(*phr))
{
return;
}
// Remember User Format
m_formatUser = UserFormat;
// Remember multi-sample type
m_desc.MultiSampleType = MultiSampleType;
// Parameter check MS types; (since swapchan bypasses
// the static Create; we need to parameter check here.)
if (MultiSampleType != D3DMULTISAMPLE_NONE)
{
*phr = pDevice->CheckDeviceMultiSampleType(RealFormat,
pDevice->SwapChain()->Windowed(),
MultiSampleType);
if (FAILED(*phr))
{
DPF_ERR("Unsupported multisample type requested. CreateRenderTarget/CreateDepthStencil failed.");
return;
}
}
// Back buffers are actually, for now, created just like other device
// surfaces.
// Otherwise, we need to call the driver
// and get ourselves a handle.
// Create a DDSURFACE and CreateSurfaceData object
DDSURFACEINFO SurfInfo;
ZeroMemory(&SurfInfo, sizeof(SurfInfo));
if ((hKernelHandle == NULL) &&
(!(pDevice->Enum()->NoDDrawSupport(pDevice->AdapterIndex())) ||
!(D3DUSAGE_PRIMARYSURFACE & Usage))
)
{
// If we are not passed a handle, then we need to get one from
// the DDI
D3D8_CREATESURFACEDATA CreateSurfaceData;
ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
// Set up the basic information
CreateSurfaceData.hDD = pDevice->GetHandle();
CreateSurfaceData.pSList = &SurfInfo;
CreateSurfaceData.dwSCnt = 1;
CreateSurfaceData.Type = D3DRTYPE_SURFACE;
CreateSurfaceData.Pool = m_desc.Pool;
CreateSurfaceData.dwUsage = m_desc.Usage;
CreateSurfaceData.Format = RealFormat;
CreateSurfaceData.MultiSampleType = MultiSampleType;
// Specify the surface data
SurfInfo.cpWidth = Width;
SurfInfo.cpHeight = Height;
*phr = pDevice->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
if (FAILED(*phr))
{
DPF_ERR("Failed to create driver surface");
return;
}
// Remember the kernel handle
SetKernelHandle(SurfInfo.hKernelHandle);
// Remember the actual pool
m_desc.Pool = CreateSurfaceData.Pool;
}
else
{
// If the caller has already allocated this
// then we assume that the pool is LocalVidMem
SurfInfo.hKernelHandle = hKernelHandle;
m_desc.Pool = D3DPOOL_LOCALVIDMEM;
}
m_desc.Size = SurfInfo.iPitch * Height;
if (m_desc.MultiSampleType != D3DMULTISAMPLE_NONE)
m_desc.Size *= (UINT)m_desc.MultiSampleType;
return;
} // CDriverSurface::CDriverSurface
#undef DPF_MODNAME
#define DPF_MODNAME "CDriverSurface::~CDriverSurface"
CDriverSurface::~CDriverSurface()
{
if (KernelHandle() != 0)
{
D3D8_DESTROYSURFACEDATA DestroyData;
ZeroMemory(&DestroyData, sizeof DestroyData);
DestroyData.hDD = Device()->GetHandle();
DestroyData.hSurface = KernelHandle();
Device()->GetHalCallbacks()->DestroySurface(&DestroyData);
}
return;
} // CDriverSurface::CDriverSurface
#undef DPF_MODNAME
#define DPF_MODNAME "CDriverSurface::LockRect"
STDMETHODIMP CDriverSurface::LockRect(D3DLOCKED_RECT *pLockedRectData,
CONST RECT *pRect,
DWORD dwFlags)
{
API_ENTER(Device());
// If parameters are bad, then we should fail some stuff
if (!VALID_WRITEPTR(pLockedRectData, sizeof(D3DLOCKED_RECT)))
{
DPF_ERR("bad pointer for m_pLockedRectData passed to LockRect");
return D3DERR_INVALIDCALL;
}
// Zero out returned data
ZeroMemory(pLockedRectData, sizeof(D3DLOCKED_RECT));
// Validate Rect
if (pRect != NULL)
{
if (!CPixel::IsValidRect(m_desc.Format,
m_desc.Width,
m_desc.Height,
pRect))
{
DPF_ERR("LockRect for a driver-allocated Surface failed");
return D3DERR_INVALIDCALL;
}
}
if (dwFlags & ~D3DLOCK_SURF_VALID)
{
DPF_ERR("Invalid dwFlags parameter passed to LockRect");
DPF_EXPLAIN_BAD_LOCK_FLAGS(0, dwFlags & ~D3DLOCK_SURF_VALID);
return D3DERR_INVALIDCALL;
}
// Can't lock surfaces that are not lockable
if (!IsLockable())
{
ReportWhyLockFailed();
return D3DERR_INVALIDCALL;
}
return InternalLockRect(pLockedRectData, pRect, dwFlags);
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDriverSurface::InternalLockRect"
HRESULT CDriverSurface::InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
CONST RECT *pRect,
DWORD dwFlags)
{
// Only one lock outstanding at a time is supported
// (even internally)
if (m_isLocked)
{
DPF_ERR("LockRect failed on a surface; surface was already locked.");
return D3DERR_INVALIDCALL;
}
D3D8_LOCKDATA lockData;
ZeroMemory(&lockData, sizeof lockData);
lockData.hDD = Device()->GetHandle();
lockData.hSurface = KernelHandle();
lockData.dwFlags = dwFlags;
if (pRect != NULL)
{
lockData.bHasRect = TRUE;
lockData.rArea = *((RECTL *) pRect);
}
else
{
DXGASSERT(lockData.bHasRect == FALSE);
}
// Sync before allowing read or write access
Sync();
HRESULT hr = Device()->GetHalCallbacks()->Lock(&lockData);
if (FAILED(hr))
{
DPF_ERR("Error trying to lock driver surface");
return hr;
}
// Fill in the Locked_Rect fields
if (CPixel::IsDXT(m_desc.Format))
{
// Pitch is the number of bytes for
// one row's worth of blocks for linear formats
// Start with our width
UINT Width = m_desc.Width;
// Convert to blocks
Width = Width / 4;
// At least one block
if (Width == 0)
Width = 1;
if (m_desc.Format == D3DFMT_DXT1)
{
// 8 bytes per block for DXT1
pLockedRectData->Pitch = Width * 8;
}
else
{
// 16 bytes per block for DXT2-5
pLockedRectData->Pitch = Width * 16;
}
}
else
{
pLockedRectData->Pitch = lockData.lPitch;
}
pLockedRectData->pBits = lockData.lpSurfData;
// Mark ourselves as locked
m_isLocked = TRUE;
// Done
return hr;
} // LockRect
#undef DPF_MODNAME
#define DPF_MODNAME "CDriverSurface::UnlockRect"
STDMETHODIMP CDriverSurface::UnlockRect()
{
API_ENTER(Device());
// If we aren't locked; then something is wrong
if (!m_isLocked)
{
DPF_ERR("UnlockRect failed; surface wasn't locked.");
return D3DERR_INVALIDCALL;
}
return InternalUnlockRect();
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDriverSurface::InternalUnlockRect"
HRESULT CDriverSurface::InternalUnlockRect()
{
DXGASSERT(m_isLocked);
D3D8_UNLOCKDATA unlockData = {
Device()->GetHandle(),
KernelHandle()
};
HRESULT hr = Device()->GetHalCallbacks()->Unlock(&unlockData);
if (SUCCEEDED(hr))
{
// Clear our locked state
m_isLocked = FALSE;
}
// Done
return hr;
} // UnlockRect
// End of file : surface.cpp