PDD_CREATESURFACEEX
コールバックシグネチャ
DWORD PDD_CREATESURFACEEX(
DD_CREATESURFACEEXDATA* param0
);パラメーター
| フィールド | 型 | 説明 |
|---|---|---|
| param0 | DD_CREATESURFACEEXDATA* | ドライバーがサーフェスを作成するために必要な情報を格納した DD_CREATESURFACEEXDATA 構造体を指します。 |
公式ドキュメント
D3dCreateSurfaceEx 関数は、Microsoft DirectDraw サーフェスと Microsoft Direct3D のハンドル値が関連付けられたことを通知し、Direct3D レンダリング用にサーフェスをセットアップできるようにします。
戻り値
D3dCreateSurfaceEx は、次のコールバックコードのいずれかを返します。
解説(Remarks)
すべての Direct3D ドライバーは D3dCreateSurfaceEx をサポートする必要があります。
D3dCreateSurfaceEx は、DirectDraw サーフェスと小さな整数値のサーフェスハンドルとの関連付けを作成します。ハンドルと DirectDraw サーフェスの間にこうした関連付けを作成することで、D3dCreateSurfaceEx はサーフェスハンドルを Direct3D コマンドストリームに埋め込めるようにします。たとえば、テクスチャマップを読み込むために D3DDP2OP_TEXBLT コマンドトークンがドライバーの D3dDrawPrimitives2 関数に送られるとき、そこでは D3dCreateSurfaceEx によって DirectDraw サーフェスに関連付けられたソースハンドルとデスティネーションハンドルが使用されます。
ローカル DirectDraw オブジェクトの配下で作成されたすべての DirectDraw サーフェスについて、ランタイムはそのサーフェスを一意に識別する有効なハンドルを生成し、DD_SURFACE_MORE 構造体の dwSurfaceHandle メンバーにそのハンドルを格納します。pcsxd が指す DD_CREATESURFACEEXDATA 構造体の lpDDSLcl メンバーは、この DD_SURFACE_MORE を指す lpSurfMore メンバーを含む DD_SURFACE_LOCAL 構造体を指します。このハンドル値は、テクスチャリングを有効にするための D3DRENDERSTATE_TEXTUREHANDLE レンダーステートでも使用され、また新しいレンダリングバッファーおよび深度バッファーを設定・クリアするための D3DDP2OP_SETRENDERTARGET コマンドおよび D3DDP2OP_CLEAR コマンドでも使用されます。Direct3D サーフェスを作成できない場合、ドライバーは呼び出しを失敗させ、DDHAL_DRIVER_HANDLED を返す必要があります。
システムメモリサーフェスとビデオメモリサーフェスのいずれについても、サーフェスの DD_SURFACE_GLOBAL 構造体および DD_SURFACE_LOCAL 構造体と dwSurfaceHandle との関連付けを通知するために D3dCreateSurfaceEx が呼び出されたとき、ディスプレイドライバーは DD_SURFACE_GLOBAL および DD_SURFACE_LOCAL の dwReserved1 メンバーに任意のデータ (たとえば、独自に割り当てたメモリへのポインター) を格納できます。これらのメンバーは、ディスプレイドライバーが独自に使用するために予約されているからです。
システムメモリサーフェスが解放されることをディスプレイドライバーに通知するために、ランタイムはそのシステムメモリサーフェスの DD_SURFACE_GLOBAL 構造体の fpVidMem ポインターメンバーを 0 に設定し、ディスプレイドライバーの D3dCreateSurfaceEx コールバックを呼び出します。ディスプレイドライバーは、このサーフェスに関連付けられたすべてのリソースを解放するのに加えて、以前に dwReserved1 メンバーに格納したデータもクリアする必要があります。なお、ビデオメモリサーフェスでも fpVidMem ポインターメンバーが 0 に設定されることがあるため、ディスプレイドライバーはサーフェスがビデオメモリとシステムメモリのどちらにあるのかを確認し、その D3dCreateSurfaceEx の呼び出しがビデオメモリサーフェスと dwSurfaceHandle の関連付けの通知なのか、それともシステムメモリサーフェスと dwSurfaceHandle の関連付け解除の通知なのかを判別する必要があります。
ビデオメモリサーフェスと dwSurfaceHandle の関連付け解除を通知するために D3dCreateSurfaceEx が呼び出されることはありません。ローカルおよび非ローカルのビデオメモリサーフェスの削除を処理し、以前に dwReserved1 メンバーに格納されたデータをクリアするのは、ディスプレイドライバーの DdDestroySurface コールバックの役割です。
ドライバーは、サーフェスを使用する際に必要となるサーフェス関連の情報も保存しておく必要があります。ドライバーは新しい lpDDLcl ごとに新しいサーフェステーブルを作成し、より多くのサーフェスを収容できるよう必要に応じてテーブルを暗黙的に拡張する必要があります。通常、これは指数的に容量を増やすアルゴリズムで行い、テーブルを頻繁に拡張せずに済むようにします。実装の詳細については、Microsoft Windows Driver Development Kit (DDK) に含まれていた Perm3 サンプルドライバーを参照してください。(DDK は Windows Driver Kit [WDK] の前身です。)
D3dCreateSurfaceEx を無効化された PDEV で呼び出せるのは、システムメモリサーフェスの場合のみです。PDEV の有効化と無効化は、ディスプレイドライバーの DrvAssertMode 関数を呼び出すことで行われます。詳細については、Managing PDEVs を参照してください。
D3dCreateSurfaceEx の実装例
LPDDRAWI_DDRAWSURFACE_LCL GetAttachedSurface(
LPDDRAWI_DDRAWSURFACE_LCL pLcl,
DDSCAPS2 * pddsCaps2)
{
LPATTACHLIST pAl;
pAl = pLcl->lpAttachList;
while (pAl) {
LPDDRAWI_DDRAWSURFACE_LCL pLclAttached = pAl->lpAttached;
LPATTACHLIST pAlAttached = pLclAttached->lpAttachList;
if ((pLclAttached->lpSurfMore->ddsCapsEx.dwCaps2 & pddsCaps2->dwCaps2) ||
(pLclAttached->lpSurfMore->ddsCapsEx.dwCaps3 & pddsCaps2->dwCaps3) ||
(pLclAttached->lpSurfMore->ddsCapsEx.dwCaps4 & pddsCaps2->dwCaps4) ||
(pLclAttached->ddsCaps.dwCaps & pddsCaps2->dwCaps)
)
{
return pLclAttached;
}
pAl = pAl->lpLink;
}
return NULL;
}
void CSExProcessPossibleMipmap(LPDDRAWI_DDRAWSURFACE_LCL pLcl)
{
//
// A more likely scenario would be to build a list of surfaces
// so that the driver can create one structure that represents the
// entire mipmap, rather than creating an object to represent each
// level as depicted here.
//
DDSCAPS2 ddsCaps2 = {0,DDSCAPS2_MIPMAPSUBLEVEL,0,0};
while (pLcl) {
//Call the private driver routine that creates a driver-side surface structure
CreateMyRepresentation(pLcl);
pLcl = GetAttachedSurface(pLcl,&ddsCaps2);
}
}
//
// The actual return type should reflect the fact that the only
// way this routine should fail is with DDERR_OUTOFMEMORY
//
void MyCreateSurfaceExHelper(LPDDRAWI_DDRAWSURFACE_LCL pLcl)
{
LPATTACHLIST pAl;
DDSCAPS2 ddsCaps2 = {0,0,0,0};
LPDDRAWI_DDRAWSURFACE_LCL pLclAttached;
LPDDRAWI_DDRAWSURFACE_LCL pLclStart;
if (pLcl->lpGbl->fpVidMem == 0) {
//A required check against bad surfaces
if (pLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
return;
//Else, this is a system memory surface, so we are being informed of
// its destruction
DestroyMyRepresentation(pLcl->lpSurfMore->dwSurfaceHandle);
return;
}
CSExProcessPossibleMipmap(pLcl);
if (pLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP) {
int i;
//
// The root surface is always positive X, so we check for the
// other five face types.
//
DWORD dw[5] = {
DDSCAPS2_CUBEMAP_NEGATIVEX,
DDSCAPS2_CUBEMAP_POSITIVEY,
DDSCAPS2_CUBEMAP_NEGATIVEY,
DDSCAPS2_CUBEMAP_POSITIVEZ,
DDSCAPS2_CUBEMAP_NEGATIVEZ};
for(i=0;i< sizeof(dw)/sizeof(dw[0]);i++) {
ddsCaps2.dwCaps2 = dw[i];
pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
if (pLclAttached)
CSExProcessPossibleMipmap(pLclAttached);
}
//
// Once we know it's a cube map, we know there cannot be any other
// attachments.
//
return;
}
//
// At this point:
// If it's a cubemap, we returned above.
// If it's a mipmap, we handled all cases above.
// The only other complex surface possibility is a primary flipping chain.
// Because a primary flipping chain cannot be mipmapped, we will simply return
// here if this surface is a mipmap.
//
if (pLcl->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
return;
//
// The only system memory surfaces we'll ever be interested in are textures (mipmaps)
// and cube maps. We do not propagate an error code for system memory
// surfaces whose format we do not understand. This could cause an error code to
// be propagated to the application when it was trying to use system memory surfaces
// of a format we do not understand, but is valid for the reference rasterizer, for example.
//
if (pLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
return;
//
// Now walk around a flipping chain. A flipping chain is a ring of
// surfaces attached to each other (each surface is attached to the next
// and to the previous surface in the ring, but not to any other surface
// in the ring).
// We need to watch out for this circular ring and make sure we exit appropriately.
// There is also the possibility of a z buffer attached to one of the surfaces
// in the ring, which may or may not have been CreateSurfaceEx'ed already.
//
pLclStart = pLcl;
while (pLcl && pLcl != pLclStart) {
//Check for Z buffer attached to this surface in the ring.
ddsCaps2.dwCaps = DDSCAPS_ZBUFFER;
ddsCaps2.dwCaps2 = 0;
pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
if (pLclAttached)
CreateMyRepresentation(pLclAttached);
//Check for stereo left surface attached to this surface in the ring
ddsCaps2.dwCaps = 0;
ddsCaps2.dwCaps2 = DDSCAPS2_STEREOSURFACELEFT;
pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
if (pLclAttached)
CreateMyRepresentation(pLclAttached);
// Move to next surface in the primary flipping ring. The next surface is
// definitely in video memory (all surfaces in an attachment structure have
// to be in the same memory type, and we excluded system memory above).
// The next surface in the ring is thus the attached video memory surface
// that is NOT a z buffer NOR a stereo left surface.
ddsCaps2.dwCaps = DDSCAPS_VIDEOMEMORY;
ddsCaps2.dwCaps2 = 0;
do {
pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
}
while (
pLclAttached->ddsCaps.dwCaps & DDSCAPS_ZBUFFER ||
pLclAttached->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT
);
pLcl = pLclAttached;
if (pLcl != pLclStart)
CreateMyRepresentation(pLcl);
}
}
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)