diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 2dd7aafa3..d150ed707 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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) - fixed: Line_SetBlocking and Line_SetTextureScale were not in the list of action specials used by DECORATE or MAPINFO. diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index f696951e1..abcd952cb 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -162,30 +162,6 @@ public: 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 -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -1709,12 +1685,14 @@ void D3DFB::ReleaseScreenshotBuffer() // //========================================================================== -IDirect3DTexture9 *D3DFB::GetCurrentScreen() +IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool) { IDirect3DTexture9 *tex; IDirect3DSurface9 *tsurf, *surf; D3DSURFACE_DESC desc; + assert(pool == D3DPOOL_SYSTEMMEM || pool == D3DPOOL_DEFAULT); + if (Windowed || PixelDoubling) { // The texture we read into must have the same pixel format as @@ -1752,8 +1730,8 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen() desc.Format = D3DFMT_A8R8G8B8; } - if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0, - desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL))) + // Read the image data into system memory. + if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0, desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL))) { return NULL; } @@ -1790,6 +1768,39 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen() 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(); return tex; } @@ -1861,7 +1872,7 @@ void D3DFB::DrawPackedTextures(int packnum) quad->ShaderNum = BQS_Plain; } quad->Palette = NULL; - quad->Texture = pack; + quad->Texture = pack->Tex; float x0 = float(x) - 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; } - QuadExtra[QuadBatchPos].Texture = tex->Box->Owner; + QuadExtra[QuadBatchPos].Texture = tex->Box->Owner->Tex; if (parms.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->Palette = NULL; - quad->Texture = tex->Box->Owner; + quad->Texture = tex->Box->Owner->Tex; vert[0].x = x0; vert[0].y = y0; @@ -3380,11 +3391,13 @@ void D3DFB::EndQuadBatch() { SetPaletteTexture(quad->Palette->Tex, quad->Palette->RoundedPaletteSize, quad->Palette->BorderColor); } +#if 0 // Set paletted bilinear filtering (IF IT WORKED RIGHT!) if ((quad->Flags & (BQF_Paletted | BQF_Bilinear)) == (BQF_Paletted | BQF_Bilinear)) { SetPalTexBilinearConstants(quad->Texture); } +#endif // Set the alpha blending SetAlphaBlend(D3DBLENDOP(quad->BlendOp), D3DBLEND(quad->SrcBlend), D3DBLEND(quad->DestBlend)); @@ -3442,7 +3455,7 @@ void D3DFB::EndQuadBatch() // Set the texture if (quad->Texture != NULL) { - SetTexture(0, quad->Texture->Tex); + SetTexture(0, quad->Texture); } // Draw the quad diff --git a/src/win32/fb_d3d9_wipe.cpp b/src/win32/fb_d3d9_wipe.cpp index 9c446a5b2..8783a2588 100644 --- a/src/win32/fb_d3d9_wipe.cpp +++ b/src/win32/fb_d3d9_wipe.cpp @@ -159,7 +159,7 @@ bool D3DFB::WipeStartScreen(int type) return false; } - InitialWipeScreen = GetCurrentScreen(); + InitialWipeScreen = GetCurrentScreen(D3DPOOL_DEFAULT); // Create another texture to copy the final wipe screen to so // 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 --------------------------------------------------------- //========================================================================== @@ -363,29 +384,12 @@ bool D3DFB::Wiper_Crossfade::Run(int ticks, D3DFB *fb) { Clock += ticks; - // Put the initial screen back to the buffer, presumably with DMA. - IDirect3DSurface9 *source = NULL, *target = NULL; - - 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(); - } + // Put the initial screen back to the buffer. + DrawScreen(fb, fb->InitialWipeScreen); // Draw the new screen on top of it. - FBVERTEX verts[4]; - - 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)); + DrawScreen(fb, fb->FinalWipeScreen, D3DBLENDOP_ADD, + D3DCOLOR_COLORVALUE(0,0,0,Clock / 32.f), D3DCOLOR_RGBA(255,255,255,0)); return Clock >= 32; } @@ -422,28 +426,8 @@ D3DFB::Wiper_Melt::Wiper_Melt() 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. - FBVERTEX verts[4]; - - 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)); + DrawScreen(fb, fb->FinalWipeScreen); int i, dy; int fbwidth = fb->Width; @@ -481,13 +465,82 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb) dpt.y += fb->LBOffsetI; 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(); - source->Release(); + fb->EndQuadBatch(); return done; } @@ -561,18 +614,7 @@ bool D3DFB::Wiper_Burn::Run(int ticks, D3DFB *fb) } // Put the initial screen back to the buffer. - IDirect3DSurface9 *source = NULL, *target; - - 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(); - } + DrawScreen(fb, fb->InitialWipeScreen); // Burn the new screen on top of it. float top = fb->LBOffset - 0.5f; diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 6cce6afe1..1684f9d82 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -289,7 +289,7 @@ private: DWORD Group1; }; D3DPal *Palette; - PackingTexture *Texture; + IDirect3DTexture9 *Texture; }; enum @@ -344,7 +344,7 @@ private: 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(); - IDirect3DTexture9 *GetCurrentScreen(); + IDirect3DTexture9 *GetCurrentScreen(D3DPOOL pool=D3DPOOL_SYSTEMMEM); void ReleaseDefaultPoolItems(); void KillNativePals(); void KillNativeTexs(); @@ -444,6 +444,9 @@ private: public: virtual ~Wiper(); 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; @@ -453,6 +456,30 @@ private: 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 #define STARTLOG do { if (!dbg) dbg = fopen ("k:/vid.log", "w"); } while(0) #define STOPLOG do { if (dbg) { fclose (dbg); dbg=NULL; } } while(0)