- 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)
- Deleted a_magewand.cpp because it only contained unused code.
- 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;
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);
}

View file

@ -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;

View file

@ -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;
}

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
@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