diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 2bfcf1955..8e7041a9e 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,11 @@ +October 7, 2009 +- Since I am currently without a primary video card and stuck with this + Mobility Radeon 9000 (on a PCI card, no less!), I have decided to give the + PS14 support some loving: D3D windowed gamma now works on these cards using + a texture lookup for the gamma table. Sadly, this halves my framerate, so + setting gamma to 1 will skip the gamma correction, as it was before, for + full speed. (On my 8800 GT, the gamma correction was free.) + October 4, 2009 (Changes by Graf Zahl) - Deleted a_magewand.cpp because it only contained unused code. - Fixed: The conversation code tried to get the player's tag instead of the diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 562abf13d..71fcca21b 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -273,10 +273,12 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) ScreenshotSurface = NULL; FinalWipeScreen = NULL; PaletteTexture = NULL; + GammaTexture = NULL; for (int i = 0; i < NUM_SHADERS; ++i) { Shaders[i] = NULL; } + GammaShader = NULL; BlockSurface[0] = NULL; BlockSurface[1] = NULL; FBFormat = D3DFMT_UNKNOWN; @@ -416,12 +418,17 @@ void D3DFB::SetInitialState() CurPixelShader = NULL; memset(Constant, 0, sizeof(Constant)); - Texture[0] = NULL; - Texture[1] = NULL; - D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, SM14 ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP); - D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, SM14 ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP); + for (int i = 0; i < countof(Texture); ++i) + { + Texture[i] = NULL; + D3DDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, (i == 1 && SM14) ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP); + D3DDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, (i == 1 && SM14) ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP); + if (i > 1) + { + // Set linear filtering for the SM14 gamma texture. + D3DDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + } NeedGammaUpdate = true; NeedPalUpdate = true; @@ -534,6 +541,7 @@ bool D3DFB::CreateResources() { return false; } + CreateGammaTexture(); CreateBlockSurfaces(); return true; } @@ -549,7 +557,7 @@ bool D3DFB::CreateResources() bool D3DFB::LoadShaders() { - static const char *const models[] = { "30/", "20/", "14/" }; + static const char models[][4] = { "30/", "20/", "14/" }; FString shaderdir, shaderpath; int model, i, lump; @@ -568,7 +576,7 @@ bool D3DFB::LoadShaders() { FMemLump data = Wads.ReadLump(lump); if (FAILED(D3DDevice->CreatePixelShader((DWORD *)data.GetMem(), &Shaders[i])) && - i != SHADER_GammaCorrection && i != SHADER_BurnWipe) + i < SHADER_BurnWipe) { break; } @@ -607,6 +615,7 @@ void D3DFB::ReleaseResources () { SAFE_RELEASE( Shaders[i] ); } + GammaShader = NULL; if (ScreenWipe != NULL) { delete ScreenWipe; @@ -782,6 +791,19 @@ bool D3DFB::CreatePaletteTexture () return true; } +bool D3DFB::CreateGammaTexture () +{ + // If this fails, you just won't get gamma correction in a window + // on SM14 cards. + assert(GammaTexture == NULL); + if (SM14) + { + return SUCCEEDED(D3DDevice->CreateTexture(256, 1, 1, 0, D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, &GammaTexture, NULL)); + } + return false; +} + bool D3DFB::CreateVertexes () { VertexPos = -1; @@ -992,8 +1014,20 @@ void D3DFB::Update () LOG("SetGammaRamp\n"); D3DDevice->SetGammaRamp(0, D3DSGR_CALIBRATE, &ramp); } + else + { + if (igamma != 1) + { + UpdateGammaTexture(igamma); + GammaShader = Shaders[SHADER_GammaCorrection]; + } + else + { + GammaShader = NULL; + } + } psgamma[2] = psgamma[1] = psgamma[0] = igamma; - psgamma[3] = 1; + psgamma[3] = 0.5; // For SM14 version D3DDevice->SetPixelShaderConstantF(PSCONST_Gamma, psgamma, 1); } @@ -1105,7 +1139,7 @@ void D3DFB::Draw3DPart(bool copy3d) D3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, vid_hwaalines); assert(OldRenderTarget == NULL); if (TempRenderTexture != NULL && - ((Windowed && Shaders[SHADER_GammaCorrection] && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen || PixelDoubling)) + ((Windowed && GammaShader && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen || PixelDoubling)) { IDirect3DSurface9 *targetsurf; if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf))) @@ -1196,12 +1230,50 @@ void D3DFB::DoWindowedGamma() D3DDevice->SetRenderTarget(0, OldRenderTarget); D3DDevice->SetFVF(D3DFVF_FBVERTEX); SetTexture(0, TempRenderTexture); - SetPixelShader(Shaders[(Windowed && Shaders[SHADER_GammaCorrection]) ? SHADER_GammaCorrection : SHADER_NormalColor]); + SetPixelShader(Windowed && GammaShader ? GammaShader : Shaders[SHADER_NormalColor]); + if (SM14 && Windowed && GammaShader) + { + SetTexture(2, GammaTexture); + SetTexture(3, GammaTexture); + SetTexture(4, GammaTexture); + } SetAlphaBlend(D3DBLENDOP(0)); EnableAlphaTest(FALSE); D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX)); OldRenderTarget->Release(); OldRenderTarget = NULL; + if (SM14 && Windowed && GammaShader) + { +// SetTexture(0, GammaTexture); +// SetPixelShader(Shaders[SHADER_NormalColor]); +// D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX)); + } + } +} + +//========================================================================== +// +// D3DFB :: UpdateGammaTexture +// +// Updates the gamma texture used by the PS14 shader. We only use the first +// half of the texture so that we needn't worry about imprecision causing +// it to grab from the border. +// +//========================================================================== + +void D3DFB::UpdateGammaTexture(float igamma) +{ + D3DLOCKED_RECT lockrect; + + if (GammaTexture != NULL && SUCCEEDED(GammaTexture->LockRect(0, &lockrect, NULL, 0))) + { + BYTE *pix = (BYTE *)lockrect.pBits; + for (int i = 0; i <= 128; ++i) + { + pix[i*4+2] = pix[i*4+1] = pix[i*4] = BYTE(255.f * powf(i / 128.f, igamma)); + pix[i*4+3] = 255; + } + GammaTexture->UnlockRect(0); } } @@ -1221,6 +1293,9 @@ void D3DFB::UploadPalette () // is similarly affected, which basically means that all Shader Model // 1.4 cards suffer from this problem, since they all use some variant // of the ATI R200. + // + // [Oh, gee. Looking over the old documentation, I guess this is + // documented that PS 1.x cards don't have a lot of precision.] skipat = SM14 ? 256 - 8 : 256; for (i = 0; i < skipat; ++i, pix += 4) @@ -3395,6 +3470,7 @@ void D3DFB::SetPixelShader(IDirect3DPixelShader9 *shader) void D3DFB::SetTexture(int tnum, IDirect3DTexture9 *texture) { + assert(tnum >= 0 && tnum < countof(Texture)); if (Texture[tnum] != texture) { Texture[tnum] = texture; @@ -3402,8 +3478,6 @@ void D3DFB::SetTexture(int tnum, IDirect3DTexture9 *texture) } } -CVAR(Float, pal, 0.5f, 0) -CVAR(Float, pc, 255.f, 0) void D3DFB::SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR border_color) { if (SM14) @@ -3430,7 +3504,7 @@ void D3DFB::SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR bo // The constant register c2 is used to hold the multiplier in the // x part and the adder in the y part. float fcount = 1 / float(count); - SetConstant(PSCONST_PaletteMod, pc * fcount, pal * fcount, 0, 0); + SetConstant(PSCONST_PaletteMod, 255 * fcount, 0.5f * fcount, 0, 0); } SetTexture(1, texture); } diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index e4c21a015..bd2c7bb81 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -336,9 +336,10 @@ private: void CreateBlockSurfaces(); bool CreateFBTexture(); bool CreatePaletteTexture(); - bool CreateGrayPaletteTexture(); + bool CreateGammaTexture(); bool CreateVertexes(); void UploadPalette(); + void UpdateGammaTexture(float igamma); void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync); void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, bool can_double, D3DCOLOR color0, D3DCOLOR color1) const; bool Reset(); @@ -381,7 +382,7 @@ private: float Constant[3][4]; D3DCOLOR CurBorderColor; IDirect3DPixelShader9 *CurPixelShader; - IDirect3DTexture9 *Texture[2]; + IDirect3DTexture9 *Texture[5]; PalEntry SourcePalette[256]; D3DCOLOR BorderColor; @@ -415,6 +416,7 @@ private: IDirect3DTexture9 *FBTexture; IDirect3DTexture9 *TempRenderTexture; IDirect3DTexture9 *PaletteTexture; + IDirect3DTexture9 *GammaTexture; IDirect3DTexture9 *ScreenshotTexture; IDirect3DSurface9 *ScreenshotSurface; @@ -429,6 +431,7 @@ private: enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType; IDirect3DPixelShader9 *Shaders[NUM_SHADERS]; + IDirect3DPixelShader9 *GammaShader; IDirect3DSurface9 *BlockSurface[2]; IDirect3DSurface9 *OldRenderTarget; diff --git a/wadsrc/static/shaders/d3d/shaders.ps b/wadsrc/static/shaders/d3d/shaders.ps index 3039c7e2a..a650cd84a 100644 --- a/wadsrc/static/shaders/d3d/shaders.ps +++ b/wadsrc/static/shaders/d3d/shaders.ps @@ -1,5 +1,10 @@ sampler2D Image : register(s0); sampler1D Palette : register(s1); +#if PS14 +sampler1D Gamma1 : register(s2); +sampler1D Gamma2 : register(s3); +sampler1D Gamma3 : register(s4); +#endif float4 PaletteMod : register(c2); float4 Weights : register(c6); // RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 } @@ -100,7 +105,19 @@ float4 InGameColormap(float2 tex_coord : TEXCOORD0, float4 color : COLOR0, float float4 GammaCorrection(float2 tex_coord : TEXCOORD0) : COLOR { float4 color = tex2D(Image, tex_coord); +#if !PS14 color.rgb = pow(color.rgb, Gamma.rgb); +#else + // On PS14 targets, we can only sample once from each sampler + // per stage. Fortunately, we have 16 samplers to play with, + // so we can just set three of them to the gamma texture and + // use one for each component. Unfortunately, all these + // texture lookups are probably not as efficient as the pow() + // solution that later targets make possible. + color.r = tex1D(Gamma1, color.r * Gamma.w).r; + color.g = tex1D(Gamma2, color.g * Gamma.w).g; + color.b = tex1D(Gamma3, color.b * Gamma.w).b; +#endif return color; } diff --git a/wadsrc/static/shaders/d3d/sm14/GammaCorrection.pso b/wadsrc/static/shaders/d3d/sm14/GammaCorrection.pso new file mode 100644 index 000000000..8abf541bc Binary files /dev/null and b/wadsrc/static/shaders/d3d/sm14/GammaCorrection.pso differ diff --git a/wadsrc/static/shaders/d3d/sm14/build.bat b/wadsrc/static/shaders/d3d/sm14/build.bat index 1ba201285..71b287ec3 100644 --- a/wadsrc/static/shaders/d3d/sm14/build.bat +++ b/wadsrc/static/shaders/d3d/sm14/build.bat @@ -22,4 +22,4 @@ fxc ..\shaders.ps /Tps_1_4 /LD -DPS14=1 /EInGameColormap -DPALTEX=1 -DINVERT=1 - fxc ..\shaders.ps /Tps_1_4 /LD -DPS14=1 /EBurnWipe /FoBurnWipe.pso -@rem PS1.4 does not support the pow instruction, so no windowed gamma correction for it. \ No newline at end of file +fxc ..\shaders.ps /Tps_1_4 /LD -DPS14=1 /EGammaCorrection /FoGammaCorrection.pso