- The initial wipe screen is now kept in video memory. I had previously

assumed that since the wipes only run at 35 FPS, the time spent DMA'ing
  it from system to video memory would be acceptable. Apparently I was wrong.
  In particular, updating the same surface several times probably has to
  synchronize between each one, making melt particularly slower than it
  needs to be.


SVN r2012 (trunk)
This commit is contained in:
Randy Heit 2009-12-01 03:15:00 +00:00
parent f722b10294
commit 80034135ef
4 changed files with 181 additions and 91 deletions

View file

@ -1,3 +1,11 @@
November 30, 2009
- The initial wipe screen is now kept in video memory. I had previously
assumed that since the wipes only run at 35 FPS, the time spent DMA'ing
it from system to video memory would be acceptable. Apparently I was wrong.
In particular, updating the same surface several times probably has to
synchronize between each one, making melt particularly slower than it
needs to be.
November 29, 2009 (Changes by Graf Zahl) November 29, 2009 (Changes by Graf Zahl)
- fixed: Line_SetBlocking and Line_SetTextureScale were not in the list - fixed: Line_SetBlocking and Line_SetTextureScale were not in the list
of action specials used by DECORATE or MAPINFO. of action specials used by DECORATE or MAPINFO.

View file

@ -162,30 +162,6 @@ public:
int RoundedPaletteSize; int RoundedPaletteSize;
}; };
// Flags for a buffered quad
enum
{
BQF_GamePalette = 1,
BQF_CustomPalette = 7,
BQF_Paletted = 7,
BQF_Bilinear = 8,
BQF_WrapUV = 16,
BQF_InvertSource = 32,
BQF_DisableAlphaTest= 64,
BQF_Desaturated = 128,
};
// Shaders for a buffered quad
enum
{
BQS_PalTex,
BQS_Plain,
BQS_RedToAlpha,
BQS_ColorOnly,
BQS_SpecialColormap,
BQS_InGameColormap,
};
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -1709,12 +1685,14 @@ void D3DFB::ReleaseScreenshotBuffer()
// //
//========================================================================== //==========================================================================
IDirect3DTexture9 *D3DFB::GetCurrentScreen() IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool)
{ {
IDirect3DTexture9 *tex; IDirect3DTexture9 *tex;
IDirect3DSurface9 *tsurf, *surf; IDirect3DSurface9 *tsurf, *surf;
D3DSURFACE_DESC desc; D3DSURFACE_DESC desc;
assert(pool == D3DPOOL_SYSTEMMEM || pool == D3DPOOL_DEFAULT);
if (Windowed || PixelDoubling) if (Windowed || PixelDoubling)
{ {
// The texture we read into must have the same pixel format as // The texture we read into must have the same pixel format as
@ -1752,8 +1730,8 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen()
desc.Format = D3DFMT_A8R8G8B8; desc.Format = D3DFMT_A8R8G8B8;
} }
if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0, // Read the image data into system memory.
desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL))) if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0, desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL)))
{ {
return NULL; return NULL;
} }
@ -1790,6 +1768,39 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen()
return NULL; return NULL;
} }
} }
// If the caller wants the screen in video memory, create a new texture, and copy back to that.
if (pool == D3DPOOL_DEFAULT)
{
IDirect3DTexture9 *vtex;
IDirect3DSurface9 *vsurf;
if (FAILED(D3DDevice->CreateTexture(FBWidth, FBHeight, 1, 0, desc.Format, D3DPOOL_DEFAULT, &vtex, NULL)))
{
surf->Release();
tex->Release();
return NULL;
}
if (FAILED(vtex->GetSurfaceLevel(0, &vsurf)))
{
vtex->Release();
surf->Release();
tex->Release();
return NULL;
}
if (FAILED(D3DDevice->UpdateSurface(surf, NULL, vsurf, NULL)))
{
vsurf->Release();
vtex->Release();
surf->Release();
tex->Release();
return NULL;
}
surf->Release();
tex->Release();
surf = vsurf;
tex = vtex;
}
surf->Release(); surf->Release();
return tex; return tex;
} }
@ -1861,7 +1872,7 @@ void D3DFB::DrawPackedTextures(int packnum)
quad->ShaderNum = BQS_Plain; quad->ShaderNum = BQS_Plain;
} }
quad->Palette = NULL; quad->Palette = NULL;
quad->Texture = pack; quad->Texture = pack->Tex;
float x0 = float(x) - 0.5f; float x0 = float(x) - 0.5f;
float y0 = float(y) - 0.5f; float y0 = float(y) - 0.5f;
@ -3007,7 +3018,7 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, double x, double y, uint32 t
return; return;
} }
QuadExtra[QuadBatchPos].Texture = tex->Box->Owner; QuadExtra[QuadBatchPos].Texture = tex->Box->Owner->Tex;
if (parms.bilinear) if (parms.bilinear)
{ {
QuadExtra[QuadBatchPos].Flags |= BQF_Bilinear; QuadExtra[QuadBatchPos].Flags |= BQF_Bilinear;
@ -3148,7 +3159,7 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
quad->ShaderNum = BQS_Plain; quad->ShaderNum = BQS_Plain;
} }
quad->Palette = NULL; quad->Palette = NULL;
quad->Texture = tex->Box->Owner; quad->Texture = tex->Box->Owner->Tex;
vert[0].x = x0; vert[0].x = x0;
vert[0].y = y0; vert[0].y = y0;
@ -3380,11 +3391,13 @@ void D3DFB::EndQuadBatch()
{ {
SetPaletteTexture(quad->Palette->Tex, quad->Palette->RoundedPaletteSize, quad->Palette->BorderColor); SetPaletteTexture(quad->Palette->Tex, quad->Palette->RoundedPaletteSize, quad->Palette->BorderColor);
} }
#if 0
// Set paletted bilinear filtering (IF IT WORKED RIGHT!) // Set paletted bilinear filtering (IF IT WORKED RIGHT!)
if ((quad->Flags & (BQF_Paletted | BQF_Bilinear)) == (BQF_Paletted | BQF_Bilinear)) if ((quad->Flags & (BQF_Paletted | BQF_Bilinear)) == (BQF_Paletted | BQF_Bilinear))
{ {
SetPalTexBilinearConstants(quad->Texture); SetPalTexBilinearConstants(quad->Texture);
} }
#endif
// Set the alpha blending // Set the alpha blending
SetAlphaBlend(D3DBLENDOP(quad->BlendOp), D3DBLEND(quad->SrcBlend), D3DBLEND(quad->DestBlend)); SetAlphaBlend(D3DBLENDOP(quad->BlendOp), D3DBLEND(quad->SrcBlend), D3DBLEND(quad->DestBlend));
@ -3442,7 +3455,7 @@ void D3DFB::EndQuadBatch()
// Set the texture // Set the texture
if (quad->Texture != NULL) if (quad->Texture != NULL)
{ {
SetTexture(0, quad->Texture->Tex); SetTexture(0, quad->Texture);
} }
// Draw the quad // Draw the quad

View file

@ -159,7 +159,7 @@ bool D3DFB::WipeStartScreen(int type)
return false; return false;
} }
InitialWipeScreen = GetCurrentScreen(); InitialWipeScreen = GetCurrentScreen(D3DPOOL_DEFAULT);
// Create another texture to copy the final wipe screen to so // Create another texture to copy the final wipe screen to so
// we can still gamma correct the wipe. Since this is just for // we can still gamma correct the wipe. Since this is just for
@ -338,6 +338,27 @@ D3DFB::Wiper::~Wiper()
{ {
} }
//==========================================================================
//
// D3DFB :: Wiper :: DrawScreen
//
// Draw either the initial or target screen completely to the screen.
//
//==========================================================================
void D3DFB::Wiper::DrawScreen(D3DFB *fb, IDirect3DTexture9 *tex,
D3DBLENDOP blendop, D3DCOLOR color0, D3DCOLOR color1)
{
FBVERTEX verts[4];
fb->CalcFullscreenCoords(verts, false, false, color0, color1);
fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX);
fb->SetTexture(0, tex);
fb->SetAlphaBlend(blendop, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
fb->SetPixelShader(fb->Shaders[SHADER_NormalColor]);
fb->D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX));
}
// WIPE: CROSSFADE --------------------------------------------------------- // WIPE: CROSSFADE ---------------------------------------------------------
//========================================================================== //==========================================================================
@ -363,29 +384,12 @@ bool D3DFB::Wiper_Crossfade::Run(int ticks, D3DFB *fb)
{ {
Clock += ticks; Clock += ticks;
// Put the initial screen back to the buffer, presumably with DMA. // Put the initial screen back to the buffer.
IDirect3DSurface9 *source = NULL, *target = NULL; DrawScreen(fb, fb->InitialWipeScreen);
if (SUCCEEDED(fb->InitialWipeScreen->GetSurfaceLevel(0, &source)) &&
SUCCEEDED(fb->D3DDevice->GetRenderTarget(0, &target)))
{
fb->D3DDevice->UpdateSurface(source, NULL, target, NULL);
target->Release();
}
if (source != NULL)
{
source->Release();
}
// Draw the new screen on top of it. // Draw the new screen on top of it.
FBVERTEX verts[4]; DrawScreen(fb, fb->FinalWipeScreen, D3DBLENDOP_ADD,
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);
fb->SetPixelShader(fb->Shaders[SHADER_NormalColor]);
fb->D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX));
return Clock >= 32; return Clock >= 32;
} }
@ -422,28 +426,8 @@ D3DFB::Wiper_Melt::Wiper_Melt()
bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb) bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
{ {
IDirect3DSurface9 *source = NULL, *target;
if (FAILED(fb->InitialWipeScreen->GetSurfaceLevel(0, &source)) ||
FAILED(fb->D3DDevice->GetRenderTarget(0, &target)))
{
// A fat lot of good we can do if we can't get these two surfaces.
if (source != NULL)
{
source->Release();
}
return true;
}
// Draw the new screen on the bottom. // Draw the new screen on the bottom.
FBVERTEX verts[4]; DrawScreen(fb, fb->FinalWipeScreen);
fb->CalcFullscreenCoords(verts, false, false, 0, 0xFFFFFFFF);
fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX);
fb->SetTexture(0, fb->FinalWipeScreen);
fb->SetAlphaBlend(D3DBLENDOP(0));
fb->SetPixelShader(fb->Shaders[SHADER_NormalColor]);
fb->D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX));
int i, dy; int i, dy;
int fbwidth = fb->Width; int fbwidth = fb->Width;
@ -481,13 +465,82 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
dpt.y += fb->LBOffsetI; dpt.y += fb->LBOffsetI;
if (rect.bottom > rect.top) if (rect.bottom > rect.top)
{ {
fb->D3DDevice->UpdateSurface(source, &rect, target, &dpt); fb->CheckQuadBatch();
BufferedQuad *quad = &fb->QuadExtra[fb->QuadBatchPos];
FBVERTEX *vert = &fb->VertexData[fb->VertexPos];
WORD *index = &fb->IndexData[fb->IndexPos];
quad->Group1 = 0;
quad->Flags = BQF_DisableAlphaTest;
quad->ShaderNum = BQS_Plain;
quad->Palette = NULL;
quad->Texture = fb->InitialWipeScreen;
// Fill the vertex buffer.
float u0 = rect.left / float(fb->FBWidth);
float v0 = 0;
float u1 = rect.right / float(fb->FBWidth);
float v1 = (rect.bottom - rect.top) / float(fb->FBHeight);
float x0 = float(rect.left) - 0.5f;
float x1 = float(rect.right) - 0.5f;
float y0 = float(dpt.y) - 0.5f;
float y1 = float(fbheight) - 0.5f;
vert[0].x = x0;
vert[0].y = y0;
vert[0].z = 0;
vert[0].rhw = 1;
vert[0].color0 = 0;
vert[0].color1 = 0xFFFFFFF;
vert[0].tu = u0;
vert[0].tv = v0;
vert[1].x = x1;
vert[1].y = y0;
vert[1].z = 0;
vert[1].rhw = 1;
vert[1].color0 = 0;
vert[1].color1 = 0xFFFFFFF;
vert[1].tu = u1;
vert[1].tv = v0;
vert[2].x = x1;
vert[2].y = y1;
vert[2].z = 0;
vert[2].rhw = 1;
vert[2].color0 = 0;
vert[2].color1 = 0xFFFFFFF;
vert[2].tu = u1;
vert[2].tv = v1;
vert[3].x = x0;
vert[3].y = y1;
vert[3].z = 0;
vert[3].rhw = 1;
vert[3].color0 = 0;
vert[3].color1 = 0xFFFFFFF;
vert[3].tu = u0;
vert[3].tv = v1;
// Fill the vertex index buffer.
index[0] = fb->VertexPos;
index[1] = fb->VertexPos + 1;
index[2] = fb->VertexPos + 2;
index[3] = fb->VertexPos;
index[4] = fb->VertexPos + 2;
index[5] = fb->VertexPos + 3;
// Batch the quad.
fb->QuadBatchPos++;
fb->VertexPos += 4;
fb->IndexPos += 6;
} }
} }
} }
} }
target->Release(); fb->EndQuadBatch();
source->Release();
return done; return done;
} }
@ -561,18 +614,7 @@ bool D3DFB::Wiper_Burn::Run(int ticks, D3DFB *fb)
} }
// Put the initial screen back to the buffer. // Put the initial screen back to the buffer.
IDirect3DSurface9 *source = NULL, *target; DrawScreen(fb, fb->InitialWipeScreen);
if (SUCCEEDED(fb->InitialWipeScreen->GetSurfaceLevel(0, &source)) &&
SUCCEEDED(fb->D3DDevice->GetRenderTarget(0, &target)))
{
fb->D3DDevice->UpdateSurface(source, NULL, target, NULL);
target->Release();
}
if (source != NULL)
{
source->Release();
}
// Burn the new screen on top of it. // Burn the new screen on top of it.
float top = fb->LBOffset - 0.5f; float top = fb->LBOffset - 0.5f;

View file

@ -289,7 +289,7 @@ private:
DWORD Group1; DWORD Group1;
}; };
D3DPal *Palette; D3DPal *Palette;
PackingTexture *Texture; IDirect3DTexture9 *Texture;
}; };
enum enum
@ -344,7 +344,7 @@ private:
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();
IDirect3DTexture9 *GetCurrentScreen(); IDirect3DTexture9 *GetCurrentScreen(D3DPOOL pool=D3DPOOL_SYSTEMMEM);
void ReleaseDefaultPoolItems(); void ReleaseDefaultPoolItems();
void KillNativePals(); void KillNativePals();
void KillNativeTexs(); void KillNativeTexs();
@ -444,6 +444,9 @@ private:
public: public:
virtual ~Wiper(); virtual ~Wiper();
virtual bool Run(int ticks, D3DFB *fb) = 0; virtual bool Run(int ticks, D3DFB *fb) = 0;
void DrawScreen(D3DFB *fb, IDirect3DTexture9 *tex,
D3DBLENDOP blendop=D3DBLENDOP(0), D3DCOLOR color0=0, D3DCOLOR color1=0xFFFFFFF);
}; };
class Wiper_Melt; friend class Wiper_Melt; class Wiper_Melt; friend class Wiper_Melt;
@ -453,6 +456,30 @@ private:
Wiper *ScreenWipe; Wiper *ScreenWipe;
}; };
// Flags for a buffered quad
enum
{
BQF_GamePalette = 1,
BQF_CustomPalette = 7,
BQF_Paletted = 7,
BQF_Bilinear = 8,
BQF_WrapUV = 16,
BQF_InvertSource = 32,
BQF_DisableAlphaTest= 64,
BQF_Desaturated = 128,
};
// Shaders for a buffered quad
enum
{
BQS_PalTex,
BQS_Plain,
BQS_RedToAlpha,
BQS_ColorOnly,
BQS_SpecialColormap,
BQS_InGameColormap,
};
#if 0 #if 0
#define STARTLOG do { if (!dbg) dbg = fopen ("k:/vid.log", "w"); } while(0) #define STARTLOG do { if (!dbg) dbg = fopen ("k:/vid.log", "w"); } while(0)
#define STOPLOG do { if (dbg) { fclose (dbg); dbg=NULL; } } while(0) #define STOPLOG do { if (dbg) { fclose (dbg); dbg=NULL; } } while(0)