diff --git a/docs/rh-log.txt b/docs/rh-log.txt index d8784959e..2161c967a 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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. diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index cdd3ee192..93cee3a34 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -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) { - RECT texrect = { 0, 0, Width, Height }; - D3DLOCKED_RECT lockrect; - if (copy3d) { + RECT texrect = { 0, 0, Width, Height }; + D3DLOCKED_RECT lockrect; + 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))) { diff --git a/src/win32/fb_d3d9_wipe.cpp b/src/win32/fb_d3d9_wipe.cpp index 01fb67fe0..5caa9b297 100644 --- a/src/win32/fb_d3d9_wipe.cpp +++ b/src/win32/fb_d3d9_wipe.cpp @@ -163,33 +163,26 @@ bool D3DFB::WipeStartScreen(int type) 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 { - // 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 (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; - } + FinalWipeScreen = TempRenderTexture; } // Make even fullscreen model render to the TempRenderTexture, so @@ -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) { diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 8c887555e..7468e072c 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -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; diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index e383f8a32..23ab38524 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -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; }