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

View file

@ -163,16 +163,10 @@ bool D3DFB::WipeStartScreen(int type)
InitialWipeScreen = GetCurrentScreen();
if (!Windowed)
{
FinalWipeScreen = TempRenderTexture;
}
else
{
// 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 (GammaFixerShader != NULL && Gamma != 1)
if (PixelDoubling || (GammaFixerShader != NULL && Windowed))
{
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
{
@ -190,7 +184,6 @@ bool D3DFB::WipeStartScreen(int type)
{
FinalWipeScreen = TempRenderTexture;
}
}
// Make even fullscreen model render to the TempRenderTexture, so
// we can have a copy of the new screen readily available.
@ -285,8 +278,7 @@ bool D3DFB::WipeDo(int ticks)
InScene = true;
}
SAFE_RELEASE( OldRenderTarget );
if (TempRenderTexture != NULL && TempRenderTexture != FinalWipeScreen &&
(Windowed && GammaFixerShader))
if (TempRenderTexture != NULL && TempRenderTexture != FinalWipeScreen)
{
IDirect3DSurface9 *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.
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->SetTexture(0, fb->FinalWipeScreen);
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.
FBVERTEX verts[4];
fb->CalcFullscreenCoords(verts, false, 0, 0xFFFFFFFF);
fb->CalcFullscreenCoords(verts, false, false, 0, 0xFFFFFFFF);
fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX);
fb->SetTexture(0, fb->FinalWipeScreen);
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));
int i, dy;
int fbwidth = fb->Width;
int fbheight = fb->Height;
bool done = true;
// 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;
POINT dpt;
dpt.x = i * fb->Width / WIDTH;
dpt.y = MAX(0, y[i] * fb->Height / HEIGHT);
dpt.x = i * fbwidth / WIDTH;
dpt.y = MAX(0, y[i] * fbheight / HEIGHT);
rect.left = dpt.x;
rect.top = fb->LBOffsetI;
rect.right = (i + 1) * fb->Width / WIDTH;
rect.bottom = fb->Height - dpt.y + fb->LBOffsetI;
rect.right = (i + 1) * fbwidth / WIDTH;
rect.bottom = fbheight - dpt.y + fb->LBOffsetI;
dpt.y += fb->LBOffsetI;
if (rect.bottom > rect.top)
{

View file

@ -79,17 +79,19 @@ class Win32Video : public IVideo
private:
struct ModeInfo
{
ModeInfo (int inX, int inY, int inBits, int inRealY)
ModeInfo (int inX, int inY, int inBits, int inRealY, int inDoubling)
: next (NULL),
width (inX),
height (inY),
bits (inBits),
realheight (inRealY)
realheight (inRealY),
doubling (inDoubling)
{}
ModeInfo *next;
int width, height, bits;
int realheight;
int doubling;
} *m_Modes;
ModeInfo *m_IteratorMode;
@ -99,11 +101,12 @@ class Win32Video : public IVideo
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 ();
static HRESULT WINAPI EnumDDModesCB (LPDDSURFACEDESC desc, void *modes);
void AddD3DModes (D3DFORMAT format);
void AddLowResModes ();
void AddLetterboxModes ();
friend class DDrawFB;
@ -296,7 +299,7 @@ private:
bool CreateVertexes();
void UploadPalette();
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();
IDirect3DTexture9 *GetCurrentScreen();
void ReleaseDefaultPoolItems();
@ -343,6 +346,7 @@ private:
PalEntry FlashColor;
int FlashAmount;
int TrueHeight;
int PixelDoubling;
int LBOffsetI;
float LBOffset;
float Gamma;

View file

@ -185,6 +185,7 @@ bool Win32Video::InitD3D9 ()
FreeModes ();
AddD3DModes (D3DFMT_X8R8G8B8);
AddD3DModes (D3DFMT_R5G6B5);
AddLowResModes ();
AddLetterboxModes ();
if (m_Modes == NULL)
{ // 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
// modes in the loop above, add the Mode X modes here.
AddMode (320, 200, 8, 200);
AddMode (320, 240, 8, 240);
AddMode (320, 200, 8, 200, 0);
AddMode (320, 240, 8, 240, 0);
}
AddLetterboxModes ();
}
@ -318,7 +319,7 @@ void Win32Video::BlankForGDI ()
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;
}
@ -332,7 +333,51 @@ void Win32Video::AddD3DModes (D3DFORMAT format)
{
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)
{
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)
{
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.
if ((x & 7) != 0 ||
@ -393,7 +438,7 @@ void Win32Video::AddMode (int x, int y, int bits, int y2)
return;
}
*probep = new ModeInfo (x, y, bits, y2);
*probep = new ModeInfo (x, y, bits, y2, doubling);
(*probep)->next = probe;
}