- Added pixel-doubled and -quadrupled screen modes to D3DFB so that users with

recent NVidia drivers can still use resolutions below 640x480, since NVidia
  saw fit to remove all support for them.


SVN r724 (trunk)
This commit is contained in:
Randy Heit 2008-01-29 18:20:05 +00:00
parent 465bcfd199
commit 59801d2b00
5 changed files with 106 additions and 56 deletions

View file

@ -1,3 +1,8 @@
January 29, 2008
- Added pixel-doubled and -quadrupled screen modes to D3DFB so that users with
recent NVidia drivers can still use resolutions below 640x480, since NVidia
saw fit to remove all support for them.
January 27, 2008 (Changes by Graf Zahl) January 27, 2008 (Changes by Graf Zahl)
- Added a PrecacheTexture virtual function to DFrameBuffer because it's the - Added a PrecacheTexture virtual function to DFrameBuffer because it's the
renderer which should decide how to precache a texture. renderer which should decide how to precache a texture.

View file

@ -257,6 +257,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen)
InScene = false; InScene = false;
QuadExtra = new BufferedQuad[MAX_QUAD_BATCH]; QuadExtra = new BufferedQuad[MAX_QUAD_BATCH];
Packs = NULL; Packs = NULL;
PixelDoubling = 0;
Gamma = 1.0; Gamma = 1.0;
FlashColor0 = 0; FlashColor0 = 0;
@ -284,6 +285,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen)
if (mode->width == Width && mode->height == Height) if (mode->width == Width && mode->height == Height)
{ {
TrueHeight = mode->realheight; TrueHeight = mode->realheight;
PixelDoubling = mode->doubling;
break; break;
} }
} }
@ -379,8 +381,8 @@ void D3DFB::FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, b
memset (pp, 0, sizeof(*pp)); memset (pp, 0, sizeof(*pp));
pp->Windowed = !fullscreen; pp->Windowed = !fullscreen;
pp->SwapEffect = D3DSWAPEFFECT_DISCARD; pp->SwapEffect = D3DSWAPEFFECT_DISCARD;
pp->BackBufferWidth = Width; pp->BackBufferWidth = Width << PixelDoubling;
pp->BackBufferHeight = TrueHeight; pp->BackBufferHeight = TrueHeight << PixelDoubling;
pp->BackBufferFormat = fullscreen ? D3DFMT_A8R8G8B8 : D3DFMT_UNKNOWN; pp->BackBufferFormat = fullscreen ? D3DFMT_A8R8G8B8 : D3DFMT_UNKNOWN;
pp->hDeviceWindow = Window; pp->hDeviceWindow = Window;
pp->PresentationInterval = vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; pp->PresentationInterval = vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
@ -632,7 +634,7 @@ bool D3DFB::CreateVertexes ()
return true; return true;
} }
void D3DFB::CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, D3DCOLOR color0, D3DCOLOR color1) const void D3DFB::CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, bool can_double, D3DCOLOR color0, D3DCOLOR color1) const
{ {
float offset = OldRenderTarget != NULL ? 0 : LBOffset; float offset = OldRenderTarget != NULL ? 0 : LBOffset;
float top = offset - 0.5f; float top = offset - 0.5f;
@ -654,9 +656,9 @@ void D3DFB::CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, D3DCOLO
else else
{ // Calculate vertices for the whole screen { // Calculate vertices for the whole screen
mxl = -0.5f; mxl = -0.5f;
mxr = float(Width) - 0.5f; mxr = float(Width << (can_double ? PixelDoubling : 0)) - 0.5f;
myt = top; myt = top;
myb = float(Height) + top; myb = float(Height << (can_double ? PixelDoubling : 0)) + top;
tmxl = 0; tmxl = 0;
tmxr = texright; tmxr = texright;
tmyt = 0; tmyt = 0;
@ -884,11 +886,11 @@ bool D3DFB::PaintToWindow ()
void D3DFB::Draw3DPart(bool copy3d) void D3DFB::Draw3DPart(bool copy3d)
{ {
RECT texrect = { 0, 0, Width, Height };
D3DLOCKED_RECT lockrect;
if (copy3d) if (copy3d)
{ {
RECT texrect = { 0, 0, Width, Height };
D3DLOCKED_RECT lockrect;
if ((FBWidth == Width && FBHeight == Height && if ((FBWidth == Width && FBHeight == Height &&
SUCCEEDED(FBTexture->LockRect (0, &lockrect, NULL, D3DLOCK_DISCARD))) || SUCCEEDED(FBTexture->LockRect (0, &lockrect, NULL, D3DLOCK_DISCARD))) ||
SUCCEEDED(FBTexture->LockRect (0, &lockrect, &texrect, 0))) SUCCEEDED(FBTexture->LockRect (0, &lockrect, &texrect, 0)))
@ -916,7 +918,7 @@ void D3DFB::Draw3DPart(bool copy3d)
D3DDevice->BeginScene(); D3DDevice->BeginScene();
assert(OldRenderTarget == NULL); assert(OldRenderTarget == NULL);
if (TempRenderTexture != NULL && if (TempRenderTexture != NULL &&
((Windowed && GammaFixerShader && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen)) ((Windowed && GammaFixerShader && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen || PixelDoubling))
{ {
IDirect3DSurface9 *targetsurf; IDirect3DSurface9 *targetsurf;
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf))) if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf)))
@ -942,7 +944,7 @@ void D3DFB::Draw3DPart(bool copy3d)
if (copy3d) if (copy3d)
{ {
FBVERTEX verts[4]; FBVERTEX verts[4];
CalcFullscreenCoords(verts, test2d, FlashColor0, FlashColor1); CalcFullscreenCoords(verts, test2d, false, FlashColor0, FlashColor1);
D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX)); D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX));
} }
} }
@ -980,7 +982,7 @@ void D3DFB::DoWindowedGamma()
{ {
FBVERTEX verts[4]; FBVERTEX verts[4];
CalcFullscreenCoords(verts, false, 0, 0xFFFFFFFF); CalcFullscreenCoords(verts, false, true, 0, 0xFFFFFFFF);
D3DDevice->SetRenderTarget(0, OldRenderTarget); D3DDevice->SetRenderTarget(0, OldRenderTarget);
D3DDevice->SetFVF(D3DFVF_FBVERTEX); D3DDevice->SetFVF(D3DFVF_FBVERTEX);
SetTexture(0, TempRenderTexture); SetTexture(0, TempRenderTexture);
@ -1176,7 +1178,7 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen()
IDirect3DSurface9 *tsurf, *surf; IDirect3DSurface9 *tsurf, *surf;
D3DSURFACE_DESC desc; D3DSURFACE_DESC desc;
if (Windowed) if (Windowed || PixelDoubling)
{ {
// The texture we read into must have the same pixel format as // The texture we read into must have the same pixel format as
// the TempRenderTexture. // the TempRenderTexture.
@ -1224,7 +1226,7 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen()
return NULL; return NULL;
} }
if (!Windowed) if (!Windowed && !PixelDoubling)
{ {
if (FAILED(D3DDevice->GetFrontBufferData(0, surf))) if (FAILED(D3DDevice->GetFrontBufferData(0, surf)))
{ {

View file

@ -163,33 +163,26 @@ bool D3DFB::WipeStartScreen(int type)
InitialWipeScreen = GetCurrentScreen(); InitialWipeScreen = GetCurrentScreen();
if (!Windowed) // Create another texture to copy the final wipe screen to so
// we can still gamma correct the wipe. Since this is just for
// gamma correction, it's okay to fail (though not desirable.)
if (PixelDoubling || (GammaFixerShader != NULL && Windowed))
{ {
FinalWipeScreen = TempRenderTexture; if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
{
if (FAILED(tsurf->GetDesc(&desc)) ||
FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height,
1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT,
&FinalWipeScreen, NULL)))
{
FinalWipeScreen = TempRenderTexture;
}
tsurf->Release();
}
} }
else else
{ {
// Create another texture to copy the final wipe screen to so FinalWipeScreen = TempRenderTexture;
// we can still gamma correct the wipe. Since this is just for
// gamma correction, it's okay to fail (though not desirable.)
if (GammaFixerShader != NULL && Gamma != 1)
{
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
{
if (FAILED(tsurf->GetDesc(&desc)) ||
FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height,
1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT,
&FinalWipeScreen, NULL)))
{
FinalWipeScreen = TempRenderTexture;
}
tsurf->Release();
}
}
else
{
FinalWipeScreen = TempRenderTexture;
}
} }
// Make even fullscreen model render to the TempRenderTexture, so // Make even fullscreen model render to the TempRenderTexture, so
@ -285,8 +278,7 @@ bool D3DFB::WipeDo(int ticks)
InScene = true; InScene = true;
} }
SAFE_RELEASE( OldRenderTarget ); SAFE_RELEASE( OldRenderTarget );
if (TempRenderTexture != NULL && TempRenderTexture != FinalWipeScreen && if (TempRenderTexture != NULL && TempRenderTexture != FinalWipeScreen)
(Windowed && GammaFixerShader))
{ {
IDirect3DSurface9 *targetsurf; IDirect3DSurface9 *targetsurf;
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf))) if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf)))
@ -390,7 +382,7 @@ bool D3DFB::Wiper_Crossfade::Run(int ticks, D3DFB *fb)
// Draw the new screen on top of it. // Draw the new screen on top of it.
FBVERTEX verts[4]; FBVERTEX verts[4];
fb->CalcFullscreenCoords(verts, false, D3DCOLOR_COLORVALUE(0,0,0,Clock / 32.f), D3DCOLOR_RGBA(255,255,255,0)); fb->CalcFullscreenCoords(verts, false, false, D3DCOLOR_COLORVALUE(0,0,0,Clock / 32.f), D3DCOLOR_RGBA(255,255,255,0));
fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX); fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX);
fb->SetTexture(0, fb->FinalWipeScreen); fb->SetTexture(0, fb->FinalWipeScreen);
fb->SetAlphaBlend(D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); fb->SetAlphaBlend(D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
@ -448,7 +440,7 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
// Draw the new screen on the bottom. // Draw the new screen on the bottom.
FBVERTEX verts[4]; FBVERTEX verts[4];
fb->CalcFullscreenCoords(verts, false, 0, 0xFFFFFFFF); fb->CalcFullscreenCoords(verts, false, false, 0, 0xFFFFFFFF);
fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX); fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX);
fb->SetTexture(0, fb->FinalWipeScreen); fb->SetTexture(0, fb->FinalWipeScreen);
fb->SetAlphaBlend(D3DBLENDOP(0)); fb->SetAlphaBlend(D3DBLENDOP(0));
@ -456,6 +448,8 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
fb->D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX)); fb->D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX));
int i, dy; int i, dy;
int fbwidth = fb->Width;
int fbheight = fb->Height;
bool done = true; bool done = true;
// Copy the old screen in vertical strips on top of the new one. // Copy the old screen in vertical strips on top of the new one.
@ -480,12 +474,12 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
RECT rect; RECT rect;
POINT dpt; POINT dpt;
dpt.x = i * fb->Width / WIDTH; dpt.x = i * fbwidth / WIDTH;
dpt.y = MAX(0, y[i] * fb->Height / HEIGHT); dpt.y = MAX(0, y[i] * fbheight / HEIGHT);
rect.left = dpt.x; rect.left = dpt.x;
rect.top = fb->LBOffsetI; rect.top = fb->LBOffsetI;
rect.right = (i + 1) * fb->Width / WIDTH; rect.right = (i + 1) * fbwidth / WIDTH;
rect.bottom = fb->Height - dpt.y + fb->LBOffsetI; rect.bottom = fbheight - dpt.y + fb->LBOffsetI;
dpt.y += fb->LBOffsetI; dpt.y += fb->LBOffsetI;
if (rect.bottom > rect.top) if (rect.bottom > rect.top)
{ {

View file

@ -79,17 +79,19 @@ class Win32Video : public IVideo
private: private:
struct ModeInfo struct ModeInfo
{ {
ModeInfo (int inX, int inY, int inBits, int inRealY) ModeInfo (int inX, int inY, int inBits, int inRealY, int inDoubling)
: next (NULL), : next (NULL),
width (inX), width (inX),
height (inY), height (inY),
bits (inBits), bits (inBits),
realheight (inRealY) realheight (inRealY),
doubling (inDoubling)
{} {}
ModeInfo *next; ModeInfo *next;
int width, height, bits; int width, height, bits;
int realheight; int realheight;
int doubling;
} *m_Modes; } *m_Modes;
ModeInfo *m_IteratorMode; ModeInfo *m_IteratorMode;
@ -99,11 +101,12 @@ class Win32Video : public IVideo
bool m_CalledCoInitialize; bool m_CalledCoInitialize;
void AddMode (int x, int y, int bits, int baseHeight); void AddMode (int x, int y, int bits, int baseHeight, int doubling);
void FreeModes (); void FreeModes ();
static HRESULT WINAPI EnumDDModesCB (LPDDSURFACEDESC desc, void *modes); static HRESULT WINAPI EnumDDModesCB (LPDDSURFACEDESC desc, void *modes);
void AddD3DModes (D3DFORMAT format); void AddD3DModes (D3DFORMAT format);
void AddLowResModes ();
void AddLetterboxModes (); void AddLetterboxModes ();
friend class DDrawFB; friend class DDrawFB;
@ -296,7 +299,7 @@ private:
bool CreateVertexes(); bool CreateVertexes();
void UploadPalette(); void UploadPalette();
void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync); void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync);
void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, D3DCOLOR color0, D3DCOLOR color1) const; void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, bool can_double, D3DCOLOR color0, D3DCOLOR color1) const;
bool Reset(); bool Reset();
IDirect3DTexture9 *GetCurrentScreen(); IDirect3DTexture9 *GetCurrentScreen();
void ReleaseDefaultPoolItems(); void ReleaseDefaultPoolItems();
@ -343,6 +346,7 @@ private:
PalEntry FlashColor; PalEntry FlashColor;
int FlashAmount; int FlashAmount;
int TrueHeight; int TrueHeight;
int PixelDoubling;
int LBOffsetI; int LBOffsetI;
float LBOffset; float LBOffset;
float Gamma; float Gamma;

View file

@ -185,6 +185,7 @@ bool Win32Video::InitD3D9 ()
FreeModes (); FreeModes ();
AddD3DModes (D3DFMT_X8R8G8B8); AddD3DModes (D3DFMT_X8R8G8B8);
AddD3DModes (D3DFMT_R5G6B5); AddD3DModes (D3DFMT_R5G6B5);
AddLowResModes ();
AddLetterboxModes (); AddLetterboxModes ();
if (m_Modes == NULL) if (m_Modes == NULL)
{ // Too bad. We didn't find any modes for D3D9. We probably won't find any { // Too bad. We didn't find any modes for D3D9. We probably won't find any
@ -259,8 +260,8 @@ void Win32Video::InitDDraw ()
{ {
// Windows 95 will let us use Mode X. If we didn't find any linear // Windows 95 will let us use Mode X. If we didn't find any linear
// modes in the loop above, add the Mode X modes here. // modes in the loop above, add the Mode X modes here.
AddMode (320, 200, 8, 200); AddMode (320, 200, 8, 200, 0);
AddMode (320, 240, 8, 240); AddMode (320, 240, 8, 240, 0);
} }
AddLetterboxModes (); AddLetterboxModes ();
} }
@ -318,7 +319,7 @@ void Win32Video::BlankForGDI ()
HRESULT WINAPI Win32Video::EnumDDModesCB (LPDDSURFACEDESC desc, void *data) HRESULT WINAPI Win32Video::EnumDDModesCB (LPDDSURFACEDESC desc, void *data)
{ {
((Win32Video *)data)->AddMode (desc->dwWidth, desc->dwHeight, 8, desc->dwHeight); ((Win32Video *)data)->AddMode (desc->dwWidth, desc->dwHeight, 8, desc->dwHeight, 0);
return DDENUMRET_OK; return DDENUMRET_OK;
} }
@ -332,7 +333,51 @@ void Win32Video::AddD3DModes (D3DFORMAT format)
{ {
if (D3D_OK == D3D->EnumAdapterModes (D3DADAPTER_DEFAULT, format, i, &mode)) if (D3D_OK == D3D->EnumAdapterModes (D3DADAPTER_DEFAULT, format, i, &mode))
{ {
AddMode (mode.Width, mode.Height, 8, mode.Height); AddMode (mode.Width, mode.Height, 8, mode.Height, 0);
}
}
}
//==========================================================================
//
// Win32Video :: AddLowResModes
//
// Recent NVidia drivers no longer support resolutions below 640x480, even
// if you try to add them as a custom resolution. With D3DFB, pixel doubling
// is quite easy to do and hardware-accelerated. If you have 1280x800, then
// you can have 320x200, but don't be surprised if it shows up as widescreen
// on a widescreen monitor, since that's what it is.
//
//==========================================================================
void Win32Video::AddLowResModes()
{
ModeInfo *mode, *nextmode;
for (mode = m_Modes; mode != NULL; mode = nextmode)
{
nextmode = mode->next;
if (mode->realheight == mode->height &&
mode->doubling == 0&&
mode->height >= 200*2 &&
mode->height <= 480*2 &&
mode->width >= 320*2 &&
mode->width <= 640*2)
{
AddMode (mode->width / 2, mode->height / 2, mode->bits, mode->height / 2, 1);
}
}
for (mode = m_Modes; mode != NULL; mode = nextmode)
{
nextmode = mode->next;
if (mode->realheight == mode->height &&
mode->doubling == 0&&
mode->height >= 200*4 &&
mode->height <= 480*4 &&
mode->width >= 320*4 &&
mode->width <= 640*4)
{
AddMode (mode->width / 4, mode->height / 4, mode->bits, mode->height / 4, 2);
} }
} }
} }
@ -349,17 +394,17 @@ void Win32Video::AddLetterboxModes ()
{ {
if (mode->width >= 360) if (mode->width >= 360)
{ {
AddMode (mode->width, mode->width * 9/16, mode->bits, mode->height); AddMode (mode->width, mode->width * 9/16, mode->bits, mode->height, mode->doubling);
} }
if (mode->width > 640) if (mode->width > 640)
{ {
AddMode (mode->width, mode->width * 10/16, mode->bits, mode->height); AddMode (mode->width, mode->width * 10/16, mode->bits, mode->height, mode->doubling);
} }
} }
} }
} }
void Win32Video::AddMode (int x, int y, int bits, int y2) void Win32Video::AddMode (int x, int y, int bits, int y2, int doubling)
{ {
// Reject modes that do not meet certain criteria. // Reject modes that do not meet certain criteria.
if ((x & 7) != 0 || if ((x & 7) != 0 ||
@ -393,7 +438,7 @@ void Win32Video::AddMode (int x, int y, int bits, int y2)
return; return;
} }
*probep = new ModeInfo (x, y, bits, y2); *probep = new ModeInfo (x, y, bits, y2, doubling);
(*probep)->next = probe; (*probep)->next = probe;
} }