|
|
/*==========================================================================;
* * 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
|