Fix constant rhythmic stutter in MFD mode 4 (split dual 640x480)
-tmfds 4 splits the 1280x480 MFD span into two independent 640x480 monitors so
the span hardware is no longer required. It rendered correctly but stuttered
rhythmically and constantly, making the game unplayable. -tmfds 1 on the same
binary was flawless.
Root cause: a cross-DirectDraw-object texture read, twice every 7-frame cycle.
CHSH_Device::InitFirst with no pOtherHSHD peer creates its OWN IDirectDraw7 (via
wDirectDrawCreateEx on that monitor's device GUID) and InitSecond creates its OWN
primary flip chain and IDirect3DDevice7. CMFDRight_Device::InitFirst passes no
peer, so the right MFD is an entirely separate DirectDraw object.
EndChannel then did, for channels 3-4:
target->pD3DDevice->SetTexture(0, pDDSTarget);
where target->pD3DDevice belonged to the RIGHT device but pDDSTarget was the LEFT
device's render-target texture. The old code comment asserted "both devices are
on the same GPU so VRAM textures are mutually accessible" -- that premise is
wrong. In DirectDraw 7 a surface belongs to the IDirectDraw7 that created it, not
to the physical GPU, so it is not a valid texture on another object's D3D device.
The MFDs still displayed, which means the runtime was emulating the access with a
VRAM -> system-memory readback and re-upload of the 1024x512 16-bit render target.
That forces a full GPU pipeline stall, and it happened on channels 3 and 4 (that
is, sh_step 5 and 6) -- twice per 7-frame cycle, on the same GPU drawing the main
view. Hence a fixed-period hitch in the whole game, forever.
This also explains why the earlier stagger work (eaa5fd3, BeginSceneRight) did not
help: it only moved a Flip from sh_step 0 to 1, and the flips already used
DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC and never blocked. The flips were never the
problem.
Fix: give the right device everything it draws with, and render channels 3-4
entirely on it.
- New HSH_CreateMFDTextures() builds the mech image atlas and the MFD sprite atlas
on a caller-supplied IDirectDraw7. Both devices now call it, so each owns a
complete independent texture set. CMFD_Device::InitSecond was refactored onto it.
- CMFDRight_Device gained its own pDDSMechTexture / pDDSDamageTexture /
pDDSTargetTexture plus a Release() override, and its InitSecond now sets up
tw/th and the material/render state exactly like the left device.
- New CMFD_Device::SwapRightState() exchanges this object's DATA members with the
right device's. BeginChannel swaps in when channel >= 3 in mode 4; EndChannel
swaps back. This routes all existing drawing to the correct monitor without
touching the ~233 mfd_device.* call sites in hudchat/huddamage/hudweapon/
GUIRadarManager. The vtable pointer is deliberately never swapped, so virtual
dispatch is unaffected; CHSHFont has no virtual functions so its array is
swapped bytewise to avoid ctor/dtor side effects on a temporary.
- EndChannel's composite is now a single path for all modes. Mode 4 composites
full 640 width at x=0 (each device is a standalone panel); modes 1-3 keep the
half-width (ch/3)*w packing into one backbuffer.
Side effects: startup builds the 65-bitmap mech atlas twice (once per device), and
VRAM use rises by a few MB. Modes 0-3 are behaviourally unchanged.
Known cosmetic leftover, deliberately not changed: huddamage.cpp lines ~1319 and
~1901 call LoadTargetTexture outside the channel-3 block, so those loads land on
the left device and go unused. The in-channel call at ~2209 runs every frame in
that branch and correctly populates the right device's copy, so behaviour is
correct -- it is just a redundant load on target change.
Requires rebuild: MW4.exe (GameOS changes recompile the engine library).
Verified: compiles clean, console launches. Two-monitor testing pending.
Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
This commit is contained in:
co-authored by
Claude Opus 5
GitHub Copilot
parent
29aee4f71b
commit
0a657b5998
@@ -613,6 +613,46 @@ char *mechnames[]={
|
||||
};
|
||||
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
// [mode 4 split-MFD fix]
|
||||
// Build the MFD texture set (mech image atlas + sprite atlas) on a given DirectDraw object.
|
||||
//
|
||||
// Mode 4 drives two physically separate 640x480 monitors. DirectDraw binds one
|
||||
// IDirectDraw7 to one monitor, so the right-hand panel necessarily has its own
|
||||
// IDirectDraw7 *and* its own IDirect3DDevice7. A DirectDraw surface belongs to the
|
||||
// IDirectDraw7 that created it - NOT to the physical GPU - so a texture made by the left
|
||||
// device can never be sampled by the right device's D3D device, even when both monitors
|
||||
// hang off the same card. Attempting it makes the runtime emulate the access with a
|
||||
// VRAM->system-memory readback every time, which stalls the whole GPU. Hence: each
|
||||
// device gets its own complete copy of these textures.
|
||||
static void HSH_CreateMFDTextures(LPDIRECTDRAW7 pdd,
|
||||
LPDIRECTDRAWSURFACE7* ppMechTexture,
|
||||
LPDIRECTDRAWSURFACE7* ppSpriteTexture)
|
||||
{
|
||||
char temppath[MAX_PATH];
|
||||
|
||||
if(g_f3dtarget){
|
||||
*ppMechTexture=CreatePixelFormatTexture(pdd,128,128,&DDPF_R5G6B5);//Texture for storing 3D mech image...
|
||||
}else{
|
||||
// MSL 5.02 Target MFD Image
|
||||
*ppMechTexture=CreatePixelFormatTexture(pdd,1024,1024,&DDPF_R5G6B5);//Texture for storing 2D mech image...
|
||||
//Store images for all mechs.
|
||||
for(int mech=0;mech<ARRAYSIZE(mechnames);mech++){
|
||||
int x=(mech%8)*128;
|
||||
int y=(mech/8)*128;
|
||||
|
||||
sprintf(temppath,"%s\\hsh\\mfd\\%s.bmp",AssetsDirectory1,mechnames[mech]);
|
||||
|
||||
DrawBitmapToSurface(*ppMechTexture,x,y,temppath);
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"mfd_texture.bmp");
|
||||
*ppSpriteTexture=CreateATextureFromFile(pdd, temppath);
|
||||
}
|
||||
|
||||
// [mode 4 split-MFD fix] exchange one data member between two devices.
|
||||
#define HSH_SWAP_MEMBER(type, a, b) { type _hsh_swaptmp = (a); (a) = (b); (b) = _hsh_swaptmp; }
|
||||
|
||||
bool CHSH_Device::InitSecond(DWORD tresx,DWORD tresy)
|
||||
{
|
||||
if (m_pOtherHSHD) {
|
||||
@@ -1068,9 +1108,9 @@ bool CMR_Device::LoadMRTargetTexture(const char *mechtexturename)
|
||||
|
||||
CMR_Device mr_device;
|
||||
|
||||
// Mode 4: the right-hand 640x480 MFD device. Shares VRAM with mfd_device
|
||||
// (same GPU), so mfd_device's pDDSTarget texture can be passed to this
|
||||
// device's pD3DDevice->SetTexture without a copy.
|
||||
// Mode 4: the right-hand 640x480 MFD device. It owns a SEPARATE IDirectDraw7 and
|
||||
// IDirect3DDevice7 (one DirectDraw device is bound to one monitor), so it also owns a
|
||||
// complete, independent copy of the MFD texture set - see HSH_CreateMFDTextures.
|
||||
CMFDRight_Device mfd_device_right;
|
||||
|
||||
bool CMFDRight_Device::InitFirst()
|
||||
@@ -1081,8 +1121,32 @@ bool CMFDRight_Device::InitFirst()
|
||||
|
||||
bool CMFDRight_Device::InitSecond()
|
||||
{
|
||||
// Create flip chain, D3D device and a render-target slot (1024x512).
|
||||
return CHSH_Device::InitSecond(1024, 512);
|
||||
// Create flip chain, D3D device, render target (1024x512) and fonts.
|
||||
CHSH_Device::InitSecond(1024, 512);
|
||||
|
||||
// Independent copy of the MFD texture set owned by THIS DirectDraw object.
|
||||
HSH_CreateMFDTextures(pDD, &pDDSMechTexture, &pDDSTexture);
|
||||
pDDSDamageTexture = 0; // created on demand by LoadDamageTexture
|
||||
pDDSTargetTexture = 0; // created on demand by LoadTargetTexture
|
||||
tw = 512;
|
||||
th = 512;
|
||||
|
||||
D3DMATERIAL7 mtrl;
|
||||
ZeroMemory( &mtrl, sizeof(mtrl) );
|
||||
mtrl.diffuse.r = mtrl.diffuse.g = mtrl.diffuse.b = 1.0f;
|
||||
mtrl.ambient.r = mtrl.ambient.g = mtrl.ambient.b = 1.0f;
|
||||
pD3DDevice->SetMaterial( &mtrl );
|
||||
pD3DDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0xffffffff );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMFDRight_Device::Release()
|
||||
{
|
||||
SAFE_RELEASE(pDDSMechTexture);
|
||||
SAFE_RELEASE(pDDSDamageTexture);
|
||||
SAFE_RELEASE(pDDSTargetTexture);
|
||||
return CHSH_Device::Release();
|
||||
}
|
||||
|
||||
/////////////////////////////////// CRadar_Device ///////////////////////////////////
|
||||
@@ -1368,7 +1432,7 @@ static DWORD channel_color[6]={
|
||||
|
||||
|
||||
CMFD_Device::CMFD_Device()
|
||||
: ch((DWORD)-1), m_pRightDevice(NULL)
|
||||
: ch((DWORD)-1), m_pRightDevice(NULL), m_bSwappedToRight(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1393,38 +1457,13 @@ bool CMFD_Device::InitFirst()
|
||||
bool CMFD_Device::InitSecond()
|
||||
{
|
||||
CHSH_Device::InitSecond(1024,512); // 640 x 480
|
||||
if(g_f3dtarget){
|
||||
pDDSMechTexture=CreatePixelFormatTexture(pDD,128,128,&DDPF_R5G6B5);//Texture for storing 3D mech image...
|
||||
}else{
|
||||
// MSL 5.02 Target MFD Image
|
||||
// pDDSMechTexture=CreatePixelFormatTexture(pDD,512,512,&DDPF_R5G6B5);//texture for storing 2D mech image...
|
||||
pDDSMechTexture=CreatePixelFormatTexture(pDD,1024,1024,&DDPF_R5G6B5);//Texture for storing 2D mech image...
|
||||
//Store images for all mechs.
|
||||
for(int mech=0;mech<ARRAYSIZE(mechnames);mech++){
|
||||
// MSL 5.02 Target MFD Image
|
||||
// int x=(mech%4)*128;
|
||||
// int y=(mech/4)*128;
|
||||
int x=(mech%8)*128;
|
||||
int y=(mech/8)*128;
|
||||
|
||||
char temppath[MAX_PATH];
|
||||
sprintf(temppath,"%s\\hsh\\mfd\\%s.bmp",AssetsDirectory1,mechnames[mech]);
|
||||
HSH_CreateMFDTextures(pDD, &pDDSMechTexture, &pDDSTexture);
|
||||
|
||||
DrawBitmapToSurface(pDDSMechTexture,x,y,temppath);
|
||||
}
|
||||
}
|
||||
//if(pDDSMechTexture==NULL)MessageBeep(0);
|
||||
//pDDSMechTexture=0;
|
||||
//pDDSDamageTexture=CreatePixelFormatTexture(pDD,512,512,&DDPF_R4G4B4A4);//damage image..
|
||||
pDDSDamageTexture=0;//On Reset: recreated... no need to create now.
|
||||
// MSL 5.03 Target Damage Display
|
||||
pDDSTargetTexture=0;
|
||||
|
||||
//////Texture
|
||||
char temppath[MAX_PATH];
|
||||
sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"mfd_texture.bmp");
|
||||
pDDSTexture=CreateATextureFromFile(pDD, temppath);
|
||||
//pDDSTexture=0;
|
||||
tw=512;
|
||||
th=512;
|
||||
|
||||
@@ -1445,6 +1484,43 @@ bool CMFD_Device::InitSecond()
|
||||
return true;
|
||||
}
|
||||
|
||||
// [mode 4 split-MFD fix]
|
||||
// Exchange this object's DATA members with the right-hand device's, so that every
|
||||
// existing "mfd_device.<member>" drawing call in hudchat/huddamage/hudweapon/radar
|
||||
// transparently targets whichever physical 640x480 panel the current channel belongs to.
|
||||
// Only data is exchanged - never the vtable pointer, so virtual dispatch is unaffected.
|
||||
void CMFD_Device::SwapRightState()
|
||||
{
|
||||
if (!m_pRightDevice)
|
||||
return;
|
||||
CMFDRight_Device* r = m_pRightDevice;
|
||||
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAW7, pDD, r->pDD);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSFront, r->pDDSFront);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSBack, r->pDDSBack);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSTarget, r->pDDSTarget);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSTexture, r->pDDSTexture);
|
||||
HSH_SWAP_MEMBER(LPDIRECT3DDEVICE7, pD3DDevice, r->pD3DDevice);
|
||||
HSH_SWAP_MEMBER(SIZE, size_back, r->size_back);
|
||||
HSH_SWAP_MEMBER(SIZE, size_target, r->size_target);
|
||||
HSH_SWAP_MEMBER(float, tw, r->tw);
|
||||
HSH_SWAP_MEMBER(float, th, r->th);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSMechTexture, r->pDDSMechTexture);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSDamageTexture, r->pDDSDamageTexture);
|
||||
HSH_SWAP_MEMBER(LPDIRECTDRAWSURFACE7, pDDSTargetTexture, r->pDDSTargetTexture);
|
||||
|
||||
// CHSHFont has no virtual functions, so a raw byte swap is safe here and avoids
|
||||
// running constructor/destructor side effects on a temporary copy.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char fonttmp[sizeof(CHSHFont)];
|
||||
memcpy(fonttmp, &pFont[i], sizeof(CHSHFont));
|
||||
memcpy(&pFont[i], &r->pFont[i], sizeof(CHSHFont));
|
||||
memcpy(&r->pFont[i], fonttmp, sizeof(CHSHFont));
|
||||
}
|
||||
|
||||
m_bSwappedToRight = !m_bSwappedToRight;
|
||||
}
|
||||
|
||||
bool CMFD_Device::BeginChannel(DWORD channel)
|
||||
{
|
||||
if (!sh_game_started)
|
||||
@@ -1491,6 +1567,13 @@ bool CMFD_Device::BeginChannel(DWORD channel)
|
||||
}
|
||||
ch=channel;
|
||||
|
||||
// [mode 4 split-MFD fix] Channels 3-4 belong to the right-hand 640x480 monitor,
|
||||
// which is a separate DirectDraw object with its own D3D device and its own copies
|
||||
// of the MFD textures and fonts. Swap our members over to it for the duration of
|
||||
// the channel so all existing drawing code targets it, and swap back in EndChannel.
|
||||
if (g_nTypeOfMFDs == 4 && m_pRightDevice && channel >= 3)
|
||||
SwapRightState();
|
||||
|
||||
//Set the Render Target.
|
||||
SetRenderTargetTexture();
|
||||
pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,0,0);
|
||||
@@ -1513,72 +1596,56 @@ bool CMFD_Device::EndChannel()
|
||||
gCaptureScreen = 0;
|
||||
}
|
||||
|
||||
// Mode 4: route this channel's blit to the correct physical monitor.
|
||||
// Handled here, before the modes 1-3 SetRenderTargetBackbuffer/BeginScene
|
||||
// block, so each path has exactly one matched Begin/EndScene pair.
|
||||
// Channels 0-2 go to the LEFT device (this, g_nMFD1).
|
||||
// Channels 3-4 go to the RIGHT device (m_pRightDevice, g_nMFD2).
|
||||
// pDDSTarget was created by this device's pDD; both devices are on the
|
||||
// same GPU so VRAM textures are mutually accessible.
|
||||
if (g_nTypeOfMFDs == 4 && m_pRightDevice) {
|
||||
CHSH_Device* target = (ch >= 3) ? m_pRightDevice : static_cast<CHSH_Device*>(this);
|
||||
target->SetRenderTargetBackbuffer();
|
||||
target->pD3DDevice->BeginScene();
|
||||
// [mode 4 split-MFD fix] One composite path for every mode. In mode 4 BeginChannel
|
||||
// has already swapped our members over to the device that owns this channel, so
|
||||
// pDDSTarget and pD3DDevice always belong to the SAME DirectDraw object. The old
|
||||
// code sampled the LEFT device's pDDSTarget from the RIGHT device's D3D device,
|
||||
// which DirectDraw cannot do natively and emulated with a VRAM->system-memory
|
||||
// readback on channels 3 and 4 - a full GPU stall twice every 7-frame cycle, which
|
||||
// is what produced the constant rhythmic stutter in mode 4.
|
||||
SetRenderTargetBackbuffer();
|
||||
pD3DDevice->BeginScene();
|
||||
|
||||
target->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
|
||||
target->pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE);
|
||||
target->pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);
|
||||
pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
|
||||
pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE);
|
||||
pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);
|
||||
|
||||
target->pD3DDevice->SetTexture(0, pDDSTarget);
|
||||
pD3DDevice->SetTexture( 0, pDDSTarget );
|
||||
|
||||
DWORD color4 = channel_color[ch];
|
||||
float w4 = (float)target->size_back.cx; // 640
|
||||
float h4 = (float)target->size_back.cy; // 480
|
||||
float w2_4 = (float)size_target.cx; // 1024
|
||||
float h2_4 = (float)size_target.cy; // 512
|
||||
D3DTLVERTEX V4[4];
|
||||
V4[0]=D3DTLVERTEX(D3DVECTOR( -0.5f,h4-0.5f,0.9f),1.0f,color4,0, 0/w2_4,h4/h2_4);
|
||||
V4[1]=D3DTLVERTEX(D3DVECTOR( -0.5f, -0.5f,0.9f),1.0f,color4,0, 0/w2_4, 0/h2_4);
|
||||
V4[2]=D3DTLVERTEX(D3DVECTOR(w4-0.5f,h4-0.5f,0.9f),1.0f,color4,0,w4/w2_4,h4/h2_4);
|
||||
V4[3]=D3DTLVERTEX(D3DVECTOR(w4-0.5f, -0.5f,0.9f),1.0f,color4,0,w4/w2_4, 0/h2_4);
|
||||
target->pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,D3DFVF_TLVERTEX,V4,4,NULL);
|
||||
DWORD color;
|
||||
|
||||
target->pD3DDevice->EndScene();
|
||||
ch = (DWORD)-1;
|
||||
color = channel_color[ch];
|
||||
D3DTLVERTEX Vertices[4]; // Vertices for the cube
|
||||
|
||||
// Modes 1-3 pack two 640-wide panels into a single backbuffer, so channels 0-2 go
|
||||
// to the left half and 3-4 to the right half. In mode 4 each device IS a
|
||||
// standalone 640x480 panel, so every channel composites full width at x=0.
|
||||
float w, x1;
|
||||
if (g_nTypeOfMFDs == 4) {
|
||||
w = (float)size_back.cx;
|
||||
x1 = 0.0f;
|
||||
} else {
|
||||
// Modes 1-3: blit to half of the single 1280-wide (or 640-wide) backbuffer.
|
||||
SetRenderTargetBackbuffer();
|
||||
pD3DDevice->BeginScene();
|
||||
|
||||
pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
|
||||
pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE);
|
||||
pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);
|
||||
|
||||
pD3DDevice->SetTexture( 0, pDDSTarget );
|
||||
|
||||
DWORD color;
|
||||
|
||||
color = channel_color[ch];
|
||||
//color = 0xFFFFFFFF;
|
||||
D3DTLVERTEX Vertices[4]; // Vertices for the cube
|
||||
|
||||
float w=(float)size_back.cx/2;//<==NOTE: this differs from radar.
|
||||
float x1=(ch/3)*w;
|
||||
float x2=x1+w;
|
||||
float h=(float)size_back.cy;
|
||||
float w2=(float)size_target.cx;
|
||||
float h2=(float)size_target.cy;
|
||||
|
||||
Vertices[0] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,h-0.5f,0.9f),1.0f,color,0, 0/w2, h/h2);
|
||||
Vertices[1] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,0-0.5f,0.9f),1.0f,color,0, 0/w2, 0/h2);
|
||||
Vertices[2] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,h-0.5f,0.9f),1.0f,color,0, w/w2, h/h2);
|
||||
Vertices[3] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,0-0.5f,0.9f),1.0f,color,0, w/w2, 0/h2);
|
||||
|
||||
pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL );
|
||||
|
||||
pD3DDevice->EndScene();
|
||||
ch = (DWORD)-1;
|
||||
w = (float)size_back.cx/2;//<==NOTE: this differs from radar.
|
||||
x1 = (ch/3)*w;
|
||||
}
|
||||
float x2=x1+w;
|
||||
float h=(float)size_back.cy;
|
||||
float w2=(float)size_target.cx;
|
||||
float h2=(float)size_target.cy;
|
||||
|
||||
Vertices[0] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,h-0.5f,0.9f),1.0f,color,0, 0/w2, h/h2);
|
||||
Vertices[1] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,0-0.5f,0.9f),1.0f,color,0, 0/w2, 0/h2);
|
||||
Vertices[2] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,h-0.5f,0.9f),1.0f,color,0, w/w2, h/h2);
|
||||
Vertices[3] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,0-0.5f,0.9f),1.0f,color,0, w/w2, 0/h2);
|
||||
|
||||
pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL );
|
||||
|
||||
pD3DDevice->EndScene();
|
||||
ch = (DWORD)-1;
|
||||
|
||||
// Hand our members back to the left device if this channel was routed right.
|
||||
if (m_bSwappedToRight)
|
||||
SwapRightState();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,10 @@ public:
|
||||
bool MapDrawn;
|
||||
};
|
||||
|
||||
// Mode 4 (split dual 640x480): the right-hand MFD lives on its own DirectDraw object,
|
||||
// so CMFD_Device keeps a typed pointer to it.
|
||||
class CMFDRight_Device;
|
||||
|
||||
class CMFD_Device:public CHSH_Device
|
||||
{
|
||||
public:
|
||||
@@ -169,7 +173,8 @@ public:
|
||||
LPDIRECTDRAWSURFACE7 pDDSTargetTexture;//Target damage texture..
|
||||
|
||||
DWORD ch; //current channel....
|
||||
CHSH_Device* m_pRightDevice; // mode 4: pointer to right 640x480 device (NULL in modes 1-3)
|
||||
CMFDRight_Device* m_pRightDevice; // mode 4: right 640x480 device (NULL in modes 1-3)
|
||||
bool m_bSwappedToRight; // mode 4: true while our members point at the right device
|
||||
public:
|
||||
CMFD_Device();
|
||||
~CMFD_Device();
|
||||
@@ -177,6 +182,7 @@ public:
|
||||
bool InitSecond();
|
||||
bool BeginChannel(DWORD channel);// Select channel 0-4.
|
||||
bool EndChannel();
|
||||
void SwapRightState(); // mode 4: exchange data members with the right device
|
||||
virtual bool BeginScene(); //Performs normal BeginScene/EndScene.
|
||||
bool BeginSceneRight(); // mode 4: clear+grid on right device at sh_step==1
|
||||
virtual bool EndScene(); //Performs the Flip.
|
||||
@@ -192,16 +198,24 @@ public:
|
||||
};
|
||||
|
||||
// Mode 4 (split dual 640x480): right-side MFD device on its own 640x480 monitor.
|
||||
// Same GPU as the left device (mfd_device), so VRAM textures are shared.
|
||||
// It owns a SEPARATE IDirectDraw7 and IDirect3DDevice7 (a DirectDraw device is bound to
|
||||
// one monitor), therefore it must also own a complete, independent copy of the MFD
|
||||
// texture set: a surface belongs to the IDirectDraw7 that created it, not to the GPU,
|
||||
// so surfaces can NOT be shared between the two devices even on the same card.
|
||||
class CMFDRight_Device : public CHSH_Device
|
||||
{
|
||||
public:
|
||||
CMFDRight_Device() {}
|
||||
LPDIRECTDRAWSURFACE7 pDDSMechTexture;
|
||||
LPDIRECTDRAWSURFACE7 pDDSDamageTexture;
|
||||
LPDIRECTDRAWSURFACE7 pDDSTargetTexture;
|
||||
public:
|
||||
CMFDRight_Device()
|
||||
: pDDSMechTexture(0), pDDSDamageTexture(0), pDDSTargetTexture(0) {}
|
||||
bool InitFirst();
|
||||
bool InitSecond();
|
||||
virtual bool BeginScene() { return true; }
|
||||
virtual bool EndScene() { return true; }
|
||||
virtual bool Release() { return CHSH_Device::Release(); }
|
||||
virtual bool Release();
|
||||
};
|
||||
|
||||
class CMR_Device:public CHSH_Device
|
||||
|
||||
Reference in New Issue
Block a user