- 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.)


SVN r1898 (trunk)
This commit is contained in:
Randy Heit 2009-10-08 04:03:32 +00:00
parent a6c387ecef
commit da31d9f8a3
6 changed files with 119 additions and 17 deletions

View file

@ -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) October 4, 2009 (Changes by Graf Zahl)
- Deleted a_magewand.cpp because it only contained unused code. - Deleted a_magewand.cpp because it only contained unused code.
- Fixed: The conversation code tried to get the player's tag instead of the - Fixed: The conversation code tried to get the player's tag instead of the

View file

@ -273,10 +273,12 @@ D3DFB::D3DFB (int width, int height, bool fullscreen)
ScreenshotSurface = NULL; ScreenshotSurface = NULL;
FinalWipeScreen = NULL; FinalWipeScreen = NULL;
PaletteTexture = NULL; PaletteTexture = NULL;
GammaTexture = NULL;
for (int i = 0; i < NUM_SHADERS; ++i) for (int i = 0; i < NUM_SHADERS; ++i)
{ {
Shaders[i] = NULL; Shaders[i] = NULL;
} }
GammaShader = NULL;
BlockSurface[0] = NULL; BlockSurface[0] = NULL;
BlockSurface[1] = NULL; BlockSurface[1] = NULL;
FBFormat = D3DFMT_UNKNOWN; FBFormat = D3DFMT_UNKNOWN;
@ -416,12 +418,17 @@ void D3DFB::SetInitialState()
CurPixelShader = NULL; CurPixelShader = NULL;
memset(Constant, 0, sizeof(Constant)); memset(Constant, 0, sizeof(Constant));
Texture[0] = NULL; for (int i = 0; i < countof(Texture); ++i)
Texture[1] = NULL; {
D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); Texture[i] = NULL;
D3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); D3DDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, (i == 1 && SM14) ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP);
D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, SM14 ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP); D3DDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, (i == 1 && SM14) ? D3DTADDRESS_BORDER : D3DTADDRESS_CLAMP);
D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, 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; NeedGammaUpdate = true;
NeedPalUpdate = true; NeedPalUpdate = true;
@ -534,6 +541,7 @@ bool D3DFB::CreateResources()
{ {
return false; return false;
} }
CreateGammaTexture();
CreateBlockSurfaces(); CreateBlockSurfaces();
return true; return true;
} }
@ -549,7 +557,7 @@ bool D3DFB::CreateResources()
bool D3DFB::LoadShaders() bool D3DFB::LoadShaders()
{ {
static const char *const models[] = { "30/", "20/", "14/" }; static const char models[][4] = { "30/", "20/", "14/" };
FString shaderdir, shaderpath; FString shaderdir, shaderpath;
int model, i, lump; int model, i, lump;
@ -568,7 +576,7 @@ bool D3DFB::LoadShaders()
{ {
FMemLump data = Wads.ReadLump(lump); FMemLump data = Wads.ReadLump(lump);
if (FAILED(D3DDevice->CreatePixelShader((DWORD *)data.GetMem(), &Shaders[i])) && if (FAILED(D3DDevice->CreatePixelShader((DWORD *)data.GetMem(), &Shaders[i])) &&
i != SHADER_GammaCorrection && i != SHADER_BurnWipe) i < SHADER_BurnWipe)
{ {
break; break;
} }
@ -607,6 +615,7 @@ void D3DFB::ReleaseResources ()
{ {
SAFE_RELEASE( Shaders[i] ); SAFE_RELEASE( Shaders[i] );
} }
GammaShader = NULL;
if (ScreenWipe != NULL) if (ScreenWipe != NULL)
{ {
delete ScreenWipe; delete ScreenWipe;
@ -782,6 +791,19 @@ bool D3DFB::CreatePaletteTexture ()
return true; 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 () bool D3DFB::CreateVertexes ()
{ {
VertexPos = -1; VertexPos = -1;
@ -992,8 +1014,20 @@ void D3DFB::Update ()
LOG("SetGammaRamp\n"); LOG("SetGammaRamp\n");
D3DDevice->SetGammaRamp(0, D3DSGR_CALIBRATE, &ramp); 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[2] = psgamma[1] = psgamma[0] = igamma;
psgamma[3] = 1; psgamma[3] = 0.5; // For SM14 version
D3DDevice->SetPixelShaderConstantF(PSCONST_Gamma, psgamma, 1); D3DDevice->SetPixelShaderConstantF(PSCONST_Gamma, psgamma, 1);
} }
@ -1105,7 +1139,7 @@ void D3DFB::Draw3DPart(bool copy3d)
D3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, vid_hwaalines); D3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, vid_hwaalines);
assert(OldRenderTarget == NULL); assert(OldRenderTarget == NULL);
if (TempRenderTexture != NULL && if (TempRenderTexture != NULL &&
((Windowed && Shaders[SHADER_GammaCorrection] && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen || PixelDoubling)) ((Windowed && GammaShader && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen || PixelDoubling))
{ {
IDirect3DSurface9 *targetsurf; IDirect3DSurface9 *targetsurf;
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf))) if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &targetsurf)))
@ -1196,12 +1230,50 @@ void D3DFB::DoWindowedGamma()
D3DDevice->SetRenderTarget(0, OldRenderTarget); D3DDevice->SetRenderTarget(0, OldRenderTarget);
D3DDevice->SetFVF(D3DFVF_FBVERTEX); D3DDevice->SetFVF(D3DFVF_FBVERTEX);
SetTexture(0, TempRenderTexture); 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)); SetAlphaBlend(D3DBLENDOP(0));
EnableAlphaTest(FALSE); EnableAlphaTest(FALSE);
D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX)); D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX));
OldRenderTarget->Release(); OldRenderTarget->Release();
OldRenderTarget = NULL; 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 // is similarly affected, which basically means that all Shader Model
// 1.4 cards suffer from this problem, since they all use some variant // 1.4 cards suffer from this problem, since they all use some variant
// of the ATI R200. // 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; skipat = SM14 ? 256 - 8 : 256;
for (i = 0; i < skipat; ++i, pix += 4) for (i = 0; i < skipat; ++i, pix += 4)
@ -3395,6 +3470,7 @@ void D3DFB::SetPixelShader(IDirect3DPixelShader9 *shader)
void D3DFB::SetTexture(int tnum, IDirect3DTexture9 *texture) void D3DFB::SetTexture(int tnum, IDirect3DTexture9 *texture)
{ {
assert(tnum >= 0 && tnum < countof(Texture));
if (Texture[tnum] != texture) if (Texture[tnum] != texture)
{ {
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) void D3DFB::SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR border_color)
{ {
if (SM14) 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 // The constant register c2 is used to hold the multiplier in the
// x part and the adder in the y part. // x part and the adder in the y part.
float fcount = 1 / float(count); 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); SetTexture(1, texture);
} }

View file

@ -336,9 +336,10 @@ private:
void CreateBlockSurfaces(); void CreateBlockSurfaces();
bool CreateFBTexture(); bool CreateFBTexture();
bool CreatePaletteTexture(); bool CreatePaletteTexture();
bool CreateGrayPaletteTexture(); bool CreateGammaTexture();
bool CreateVertexes(); bool CreateVertexes();
void UploadPalette(); void UploadPalette();
void UpdateGammaTexture(float igamma);
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, bool can_double, 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();
@ -381,7 +382,7 @@ private:
float Constant[3][4]; float Constant[3][4];
D3DCOLOR CurBorderColor; D3DCOLOR CurBorderColor;
IDirect3DPixelShader9 *CurPixelShader; IDirect3DPixelShader9 *CurPixelShader;
IDirect3DTexture9 *Texture[2]; IDirect3DTexture9 *Texture[5];
PalEntry SourcePalette[256]; PalEntry SourcePalette[256];
D3DCOLOR BorderColor; D3DCOLOR BorderColor;
@ -415,6 +416,7 @@ private:
IDirect3DTexture9 *FBTexture; IDirect3DTexture9 *FBTexture;
IDirect3DTexture9 *TempRenderTexture; IDirect3DTexture9 *TempRenderTexture;
IDirect3DTexture9 *PaletteTexture; IDirect3DTexture9 *PaletteTexture;
IDirect3DTexture9 *GammaTexture;
IDirect3DTexture9 *ScreenshotTexture; IDirect3DTexture9 *ScreenshotTexture;
IDirect3DSurface9 *ScreenshotSurface; IDirect3DSurface9 *ScreenshotSurface;
@ -429,6 +431,7 @@ private:
enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType; enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType;
IDirect3DPixelShader9 *Shaders[NUM_SHADERS]; IDirect3DPixelShader9 *Shaders[NUM_SHADERS];
IDirect3DPixelShader9 *GammaShader;
IDirect3DSurface9 *BlockSurface[2]; IDirect3DSurface9 *BlockSurface[2];
IDirect3DSurface9 *OldRenderTarget; IDirect3DSurface9 *OldRenderTarget;

View file

@ -1,5 +1,10 @@
sampler2D Image : register(s0); sampler2D Image : register(s0);
sampler1D Palette : register(s1); sampler1D Palette : register(s1);
#if PS14
sampler1D Gamma1 : register(s2);
sampler1D Gamma2 : register(s3);
sampler1D Gamma3 : register(s4);
#endif
float4 PaletteMod : register(c2); float4 PaletteMod : register(c2);
float4 Weights : register(c6); // RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 } 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 GammaCorrection(float2 tex_coord : TEXCOORD0) : COLOR
{ {
float4 color = tex2D(Image, tex_coord); float4 color = tex2D(Image, tex_coord);
#if !PS14
color.rgb = pow(color.rgb, Gamma.rgb); 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; return color;
} }

Binary file not shown.

View file

@ -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 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. fxc ..\shaders.ps /Tps_1_4 /LD -DPS14=1 /EGammaCorrection /FoGammaCorrection.pso