2009-09-13 17:46:33 +00:00
|
|
|
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
|
|
|
#include "D3DBase.h"
|
|
|
|
#include "Render.h"
|
|
|
|
#include "FramebufferManager.h"
|
2009-10-08 00:35:47 +00:00
|
|
|
#include "VideoConfig.h"
|
2010-03-14 18:57:50 +00:00
|
|
|
#include "PixelShaderCache.h"
|
|
|
|
#include "VertexShaderCache.h"
|
|
|
|
#include "TextureConverter.h"
|
2009-09-13 17:46:33 +00:00
|
|
|
|
|
|
|
#undef CHECK
|
2009-10-25 02:35:21 +00:00
|
|
|
#define CHECK(hr,Message) if (FAILED(hr)) { PanicAlert(__FUNCTION__ " FAIL: %s" ,Message); }
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
FramebufferManager FBManager;
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorRTSurface()
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
|
|
|
return s_efb_color_surface;
|
|
|
|
}
|
2010-03-14 18:57:50 +00:00
|
|
|
|
|
|
|
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthRTSurface()
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
|
|
|
return s_efb_depth_surface;
|
|
|
|
}
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorOffScreenRTSurface()
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
|
|
|
return s_efb_color_OffScreenReadBuffer;
|
|
|
|
}
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthOffScreenRTSurface()
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
|
|
|
return s_efb_depth_OffScreenReadBuffer;
|
|
|
|
}
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorReadSurface()
|
2009-11-22 02:37:00 +00:00
|
|
|
{
|
2009-11-08 20:35:11 +00:00
|
|
|
return s_efb_color_ReadBuffer;
|
|
|
|
}
|
2009-11-22 02:37:00 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthReadSurface()
|
2009-11-22 02:37:00 +00:00
|
|
|
{
|
2009-11-08 20:35:11 +00:00
|
|
|
return s_efb_depth_ReadBuffer;
|
|
|
|
}
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
D3DFORMAT FramebufferManager::GetEFBDepthRTSurfaceFormat(){return s_efb_depth_surface_Format;}
|
|
|
|
D3DFORMAT FramebufferManager::GetEFBDepthReadSurfaceFormat(){return s_efb_depth_ReadBuffer_Format;}
|
|
|
|
D3DFORMAT FramebufferManager::GetEFBColorRTSurfaceFormat(){return s_efb_color_surface_Format;}
|
2009-09-13 17:46:33 +00:00
|
|
|
|
2009-11-22 02:37:00 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
|
2009-09-15 20:18:25 +00:00
|
|
|
{
|
|
|
|
return s_efb_color_texture;
|
|
|
|
}
|
|
|
|
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture(const EFBRectangle &sourceRc)
|
2009-09-15 21:05:31 +00:00
|
|
|
{
|
2009-10-10 23:36:18 +00:00
|
|
|
return s_efb_depth_texture;
|
2009-09-15 21:05:31 +00:00
|
|
|
}
|
|
|
|
|
2009-11-22 02:37:00 +00:00
|
|
|
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
void FramebufferManager::Create()
|
2009-11-22 02:37:00 +00:00
|
|
|
{
|
2009-09-13 17:46:33 +00:00
|
|
|
// Simplest possible setup to start with.
|
ok big changes here:
in videocommon little fix for the alpha test values, return to the original values as they are more accurate.
in D3D:
huge change in state management, now all the state management is centralized and redundant state changes are eliminated.
Fixed the overlapped viewport error in non ati cards:
the error was caused by this: when a viewport is defined larger than the current rendertarget, an error is thrown and the last valid viewport is used, this is the reference behavior, in ati cards if a larger viewport is defined, no eror is returned, the rendering is valid and is rendered using the projection defined by the viewport but limited to the rendertarget are, exactly like opengl or the GC hardware.
to solve this in reference drivers defined a large rendertarget (2x the size of the original) and proceed to render in a centered quad insithe the larger rendertarget, in this way larger viewports always falls inside a valid rendertarget size, the drawback of this is the waste of resources. it can be dynamized, depending or games or changed at runtime when a oversized viewport is detected, but i live that to future commits.
please test this and let me know the results.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4841 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-01-15 15:52:08 +00:00
|
|
|
int target_width = Renderer::GetFullTargetWidth();
|
|
|
|
int target_height = Renderer::GetFullTargetHeight();
|
2009-12-22 06:47:42 +00:00
|
|
|
|
2009-10-06 14:24:10 +00:00
|
|
|
s_efb_color_surface_Format = D3DFMT_A8R8G8B8;
|
2009-10-10 23:36:18 +00:00
|
|
|
//get the framebuffer texture
|
2009-11-08 20:35:11 +00:00
|
|
|
HRESULT hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
2009-09-15 20:18:25 +00:00
|
|
|
D3DPOOL_DEFAULT, &s_efb_color_texture, NULL);
|
2009-11-08 20:35:11 +00:00
|
|
|
if(s_efb_color_texture)
|
|
|
|
{
|
2009-11-22 02:37:00 +00:00
|
|
|
hr = s_efb_color_texture->GetSurfaceLevel(0,&s_efb_color_surface);
|
2009-11-08 20:35:11 +00:00
|
|
|
}
|
2009-10-10 23:36:18 +00:00
|
|
|
CHECK(hr,"Create Color Texture");
|
2009-11-08 20:35:11 +00:00
|
|
|
hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
|
|
D3DPOOL_DEFAULT, &s_efb_colorRead_texture, NULL);
|
|
|
|
CHECK(hr,"Create Color Read Texture");
|
|
|
|
if(s_efb_colorRead_texture)
|
2009-10-10 23:36:18 +00:00
|
|
|
{
|
2009-11-08 20:35:11 +00:00
|
|
|
s_efb_colorRead_texture->GetSurfaceLevel(0,&s_efb_color_ReadBuffer);
|
2009-10-10 23:36:18 +00:00
|
|
|
}
|
2009-11-08 20:35:11 +00:00
|
|
|
//create an offscreen surface that we can lock to retrieve the data
|
|
|
|
hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, s_efb_color_surface_Format, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreenReadBuffer, NULL );
|
|
|
|
CHECK(hr,"Create Color offScreen Surface");
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2009-10-06 14:24:10 +00:00
|
|
|
//Select Zbuffer format supported by hadware.
|
2009-10-08 00:35:47 +00:00
|
|
|
if (g_ActiveConfig.bEFBAccessEnable)
|
2009-11-22 02:37:00 +00:00
|
|
|
{
|
|
|
|
D3DFORMAT *DepthTexFormats = new D3DFORMAT[5];
|
|
|
|
DepthTexFormats[0] = FOURCC_INTZ;
|
|
|
|
DepthTexFormats[1] = FOURCC_DF24;
|
|
|
|
DepthTexFormats[2] = FOURCC_RAWZ;
|
|
|
|
DepthTexFormats[3] = FOURCC_DF16;
|
|
|
|
DepthTexFormats[4] = D3DFMT_D24X8;
|
|
|
|
|
|
|
|
for(int i = 0;i<5;i++)
|
|
|
|
{
|
|
|
|
s_efb_depth_surface_Format = DepthTexFormats[i];
|
|
|
|
//get the framebuffer Depth texture
|
|
|
|
hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format,
|
|
|
|
D3DPOOL_DEFAULT, &s_efb_depth_texture, NULL);
|
|
|
|
if (!FAILED(hr)) break;
|
|
|
|
}
|
|
|
|
CHECK(hr,"Depth Color Texture");
|
|
|
|
//get the Surface
|
|
|
|
if(s_efb_depth_texture)
|
|
|
|
{
|
|
|
|
s_efb_depth_texture->GetSurfaceLevel(0,&s_efb_depth_surface);
|
|
|
|
}
|
|
|
|
//create a 4x4 pixel texture to work as a buffer for peeking
|
|
|
|
if(s_efb_depth_surface_Format == FOURCC_RAWZ || s_efb_depth_surface_Format == D3DFMT_D24X8)
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
2009-11-22 02:37:00 +00:00
|
|
|
DepthTexFormats[0] = D3DFMT_A8R8G8B8;
|
2009-11-08 20:35:11 +00:00
|
|
|
}
|
2009-11-10 12:45:03 +00:00
|
|
|
else
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
2009-11-22 02:37:00 +00:00
|
|
|
DepthTexFormats[0] = D3DFMT_R32F;
|
2009-11-08 20:35:11 +00:00
|
|
|
}
|
2009-11-22 02:37:00 +00:00
|
|
|
DepthTexFormats[1] = D3DFMT_A8R8G8B8;
|
|
|
|
|
|
|
|
for(int i = 0;i<2;i++)
|
|
|
|
{
|
|
|
|
s_efb_depth_ReadBuffer_Format = DepthTexFormats[i];
|
|
|
|
//get the framebuffer Depth texture
|
|
|
|
hr = D3D::dev->CreateTexture(4, 4, 1, D3DUSAGE_RENDERTARGET, s_efb_depth_ReadBuffer_Format,
|
|
|
|
D3DPOOL_DEFAULT, &s_efb_depthRead_texture, NULL);
|
|
|
|
if (!FAILED(hr)) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(hr,"Create Depth Read texture");
|
|
|
|
if(s_efb_depthRead_texture)
|
|
|
|
{
|
|
|
|
s_efb_depthRead_texture->GetSurfaceLevel(0,&s_efb_depth_ReadBuffer);
|
|
|
|
}
|
|
|
|
//create an offscreen surface that we can lock to retrieve the data
|
|
|
|
hr = D3D::dev->CreateOffscreenPlainSurface(4, 4, s_efb_depth_ReadBuffer_Format, D3DPOOL_SYSTEMMEM, &s_efb_depth_OffScreenReadBuffer, NULL );
|
|
|
|
CHECK(hr,"Create Depth offScreen Surface");
|
|
|
|
delete [] DepthTexFormats;
|
2009-10-08 00:35:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-10 23:36:18 +00:00
|
|
|
s_efb_depth_surface_Format = D3DFMT_D24X8;
|
|
|
|
hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, s_efb_depth_surface_Format,
|
2009-10-08 00:35:47 +00:00
|
|
|
D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL);
|
2009-11-22 02:37:00 +00:00
|
|
|
CHECK(hr,"CreateDepthStencilSurface");
|
2009-10-08 00:35:47 +00:00
|
|
|
}
|
2009-09-13 17:46:33 +00:00
|
|
|
}
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
void FramebufferManager::Destroy()
|
|
|
|
{
|
|
|
|
if (s_efb_depth_surface)
|
|
|
|
s_efb_depth_surface->Release();
|
|
|
|
s_efb_depth_surface=NULL;
|
|
|
|
|
|
|
|
if (s_efb_color_surface)
|
|
|
|
s_efb_color_surface->Release();
|
|
|
|
s_efb_color_surface=NULL;
|
|
|
|
|
|
|
|
if (s_efb_color_ReadBuffer)
|
|
|
|
s_efb_color_ReadBuffer->Release();
|
|
|
|
s_efb_color_ReadBuffer=NULL;
|
|
|
|
|
|
|
|
if (s_efb_depth_ReadBuffer)
|
|
|
|
s_efb_depth_ReadBuffer->Release();
|
|
|
|
s_efb_depth_ReadBuffer=NULL;
|
|
|
|
|
|
|
|
if (s_efb_color_OffScreenReadBuffer)
|
|
|
|
s_efb_color_OffScreenReadBuffer->Release();
|
|
|
|
s_efb_color_OffScreenReadBuffer=NULL;
|
|
|
|
|
|
|
|
if (s_efb_depth_OffScreenReadBuffer)
|
|
|
|
s_efb_depth_OffScreenReadBuffer->Release();
|
|
|
|
s_efb_depth_OffScreenReadBuffer=NULL;
|
|
|
|
|
|
|
|
if (s_efb_color_texture)
|
|
|
|
s_efb_color_texture->Release();
|
|
|
|
s_efb_color_texture=NULL;
|
|
|
|
|
|
|
|
if (s_efb_colorRead_texture)
|
|
|
|
s_efb_colorRead_texture->Release();
|
|
|
|
s_efb_colorRead_texture=NULL;
|
|
|
|
|
|
|
|
if (s_efb_depth_texture)
|
|
|
|
s_efb_depth_texture->Release();
|
|
|
|
s_efb_depth_texture=NULL;
|
|
|
|
|
|
|
|
if (s_efb_depthRead_texture)
|
|
|
|
s_efb_depthRead_texture->Release();
|
|
|
|
s_efb_depthRead_texture=NULL;
|
|
|
|
|
|
|
|
for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
|
|
|
|
{
|
fixed fps limiting when using using virtual xfb, now fps = vps, in fact now real xfb is as fast as no using xfb, i'm thinking now that the correct thing is leave it enabled as default, and even remove the option.
the problem is one strange behavior i found, in opengl when xfb is enable, frame limit causes the frame rate to be limited exact half the correct speed, so if you choose auto and the game uses 30 fps you get 15 fps
so in opengl, you have to limit to the exact double of the game speed, 100 to pal games and 120 to ntsc.
in d3d this not happened every time, it just happen when you change some time consuming setting like changing the ssaa or resizing the window, in that case you have to disable and re enable frame limit to get the correct fps
to all the devs please if you can help me debug this, will give you a lot of thanks as i'm short in time to debug this error and is driving me crazy not to find the source of the problem.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5249 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-28 23:51:32 +00:00
|
|
|
if(it->xfbSource.texture)
|
|
|
|
it->xfbSource.texture->Release();
|
2010-03-14 18:57:50 +00:00
|
|
|
}
|
|
|
|
m_virtualXFBList.clear();
|
|
|
|
if(m_realXFBSource.texture)
|
|
|
|
m_realXFBSource.texture->Release();
|
|
|
|
m_realXFBSource.texture = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
2009-09-13 17:46:33 +00:00
|
|
|
{
|
2010-03-14 18:57:50 +00:00
|
|
|
if (g_ActiveConfig.bUseRealXFB)
|
|
|
|
copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
|
|
|
else
|
|
|
|
copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
|
|
|
}
|
2009-10-08 00:35:47 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
const XFBSource** FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
|
|
{
|
|
|
|
if (g_ActiveConfig.bUseRealXFB)
|
|
|
|
return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
|
|
|
else
|
|
|
|
return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
FramebufferManager::VirtualXFBListType::iterator FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
|
|
|
{
|
|
|
|
u32 srcLower = xfbAddr;
|
|
|
|
u32 srcUpper = xfbAddr + 2 * width * height;
|
|
|
|
|
|
|
|
VirtualXFBListType::iterator it;
|
|
|
|
for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
|
|
|
|
{
|
|
|
|
u32 dstLower = it->xfbAddr;
|
|
|
|
u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
|
|
|
|
|
|
|
|
if (dstLower >= srcLower && dstUpper <= srcUpper)
|
|
|
|
return it;
|
|
|
|
}
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
// That address is not in the Virtual XFB list.
|
|
|
|
return m_virtualXFBList.end();
|
|
|
|
}
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
void FramebufferManager::replaceVirtualXFB()
|
|
|
|
{
|
|
|
|
VirtualXFBListType::iterator it = m_virtualXFBList.begin();
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
s32 srcLower = it->xfbAddr;
|
|
|
|
s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
|
|
|
|
s32 lineSize = 2 * it->xfbWidth;
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
it++;
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
while (it != m_virtualXFBList.end())
|
|
|
|
{
|
|
|
|
s32 dstLower = it->xfbAddr;
|
|
|
|
s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
if (dstLower >= srcLower && dstUpper <= srcUpper)
|
|
|
|
{
|
|
|
|
// invalidate the data
|
|
|
|
it->xfbAddr = 0;
|
|
|
|
it->xfbHeight = 0;
|
|
|
|
it->xfbWidth = 0;
|
|
|
|
}
|
|
|
|
else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
|
|
|
|
{
|
|
|
|
s32 upperOverlap = (srcUpper - dstLower) / lineSize;
|
|
|
|
s32 lowerOverlap = (dstUpper - srcLower) / lineSize;
|
|
|
|
|
|
|
|
if (upperOverlap > 0 && lowerOverlap < 0)
|
|
|
|
{
|
|
|
|
it->xfbAddr += lineSize * upperOverlap;
|
|
|
|
it->xfbHeight -= upperOverlap;
|
|
|
|
}
|
|
|
|
else if (lowerOverlap > 0)
|
|
|
|
{
|
|
|
|
it->xfbHeight -= lowerOverlap;
|
|
|
|
}
|
|
|
|
}
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
2009-11-08 20:35:11 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
|
|
{
|
|
|
|
u8* xfb_in_ram = Memory_GetPtr(xfbAddr);
|
|
|
|
if (!xfb_in_ram)
|
|
|
|
{
|
|
|
|
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
|
|
|
|
return;
|
|
|
|
}
|
2009-10-10 23:36:18 +00:00
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc);
|
|
|
|
TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight);
|
2009-09-13 17:46:33 +00:00
|
|
|
}
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
|
|
{
|
|
|
|
LPDIRECT3DTEXTURE9 xfbTexture;
|
2010-04-03 22:22:55 +00:00
|
|
|
HRESULT hr = 0;
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
|
|
|
|
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight);
|
|
|
|
|
|
|
|
if (it == m_virtualXFBList.end() && (int)m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
|
|
|
|
{
|
|
|
|
// replace the last virtual XFB
|
|
|
|
it--;
|
|
|
|
}
|
|
|
|
|
|
|
|
float MultiSampleCompensation = 1.0f;
|
|
|
|
if(g_ActiveConfig.iMultisampleMode > 0 && g_ActiveConfig.iMultisampleMode < 4)
|
|
|
|
{
|
|
|
|
switch (g_ActiveConfig.iMultisampleMode)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
MultiSampleCompensation = 2.0f/3.0f;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
MultiSampleCompensation = 0.5f;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
MultiSampleCompensation = 1.0f/3.0f;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
float scaleX = Renderer::GetTargetScaleX() * MultiSampleCompensation ;
|
|
|
|
float scaleY = Renderer::GetTargetScaleY() * MultiSampleCompensation;
|
|
|
|
TargetRectangle targetSource,efbSource;
|
|
|
|
efbSource = Renderer::ConvertEFBRectangle(sourceRc);
|
|
|
|
targetSource.top = (sourceRc.top *scaleY);
|
|
|
|
targetSource.bottom = (sourceRc.bottom *scaleY);
|
|
|
|
targetSource.left = (sourceRc.left *scaleX);
|
|
|
|
targetSource.right = (sourceRc.right * scaleX);
|
|
|
|
int target_width = targetSource.right - targetSource.left;
|
|
|
|
int target_height = targetSource.bottom - targetSource.top;
|
|
|
|
if (it != m_virtualXFBList.end())
|
|
|
|
{
|
|
|
|
// Overwrite an existing Virtual XFB.
|
|
|
|
|
|
|
|
it->xfbAddr = xfbAddr;
|
|
|
|
it->xfbWidth = fbWidth;
|
|
|
|
it->xfbHeight = fbHeight;
|
|
|
|
|
|
|
|
it->xfbSource.srcAddr = xfbAddr;
|
|
|
|
it->xfbSource.srcWidth = fbWidth;
|
|
|
|
it->xfbSource.srcHeight = fbHeight;
|
|
|
|
|
2010-04-03 22:22:55 +00:00
|
|
|
if(it->xfbSource.texWidth != target_width || it->xfbSource.texHeight != target_height || !(it->xfbSource.texture))
|
2010-03-14 18:57:50 +00:00
|
|
|
{
|
|
|
|
if(it->xfbSource.texture)
|
|
|
|
it->xfbSource.texture->Release();
|
2010-04-03 22:22:55 +00:00
|
|
|
it->xfbSource.texture = NULL;
|
|
|
|
hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
|
|
D3DPOOL_DEFAULT, &(it->xfbSource.texture), NULL);
|
|
|
|
|
2010-03-14 18:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xfbTexture = it->xfbSource.texture;
|
|
|
|
|
|
|
|
it->xfbSource.texWidth = target_width;
|
|
|
|
it->xfbSource.texHeight = target_height;
|
|
|
|
|
|
|
|
// Move this Virtual XFB to the front of the list.
|
|
|
|
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
|
|
|
|
|
|
|
|
// Keep stale XFB data from being used
|
|
|
|
replaceVirtualXFB();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Create a new Virtual XFB and place it at the front of the list.
|
|
|
|
|
|
|
|
D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
|
|
D3DPOOL_DEFAULT, &xfbTexture, NULL);
|
|
|
|
VirtualXFB newVirt;
|
|
|
|
|
|
|
|
newVirt.xfbAddr = xfbAddr;
|
|
|
|
newVirt.xfbWidth = fbWidth;
|
|
|
|
newVirt.xfbHeight = fbHeight;
|
|
|
|
|
|
|
|
newVirt.xfbSource.texture = xfbTexture;
|
|
|
|
newVirt.xfbSource.texWidth = target_width;
|
|
|
|
newVirt.xfbSource.texHeight = target_height;
|
|
|
|
|
|
|
|
// Add the new Virtual XFB to the list
|
|
|
|
|
|
|
|
if ((int)m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
|
|
|
|
{
|
|
|
|
// List overflowed; delete the oldest.
|
|
|
|
m_virtualXFBList.back().xfbSource.texture->Release();
|
|
|
|
m_virtualXFBList.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_virtualXFBList.push_front(newVirt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy EFB to XFB texture
|
|
|
|
|
|
|
|
if(!xfbTexture)
|
|
|
|
return;
|
|
|
|
LPDIRECT3DTEXTURE9 read_texture = GetEFBColorTexture(sourceRc);
|
|
|
|
|
|
|
|
Renderer::ResetAPIState(); // reset any game specific settings
|
|
|
|
LPDIRECT3DSURFACE9 Rendersurf = NULL;
|
|
|
|
|
|
|
|
xfbTexture->GetSurfaceLevel(0,&Rendersurf);
|
|
|
|
D3D::dev->SetDepthStencilSurface(NULL);
|
|
|
|
D3D::dev->SetRenderTarget(0, Rendersurf);
|
|
|
|
|
|
|
|
D3DVIEWPORT9 vp;
|
|
|
|
|
|
|
|
vp.X = 0;
|
|
|
|
vp.Y = 0;
|
|
|
|
vp.Width = target_width;
|
|
|
|
vp.Height = target_height;
|
|
|
|
vp.MinZ = 0.0f;
|
|
|
|
vp.MaxZ = 1.0f;
|
|
|
|
D3D::dev->SetViewport(&vp);
|
|
|
|
RECT sourcerect;
|
|
|
|
sourcerect.bottom = efbSource.bottom;
|
|
|
|
sourcerect.left = efbSource.left;
|
|
|
|
sourcerect.right = efbSource.right;
|
|
|
|
sourcerect.top = efbSource.top;
|
|
|
|
|
|
|
|
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
|
|
D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
|
|
|
|
|
|
|
|
|
|
int SSAAMode = ( g_ActiveConfig.iMultisampleMode > 3 )? 0 : g_ActiveConfig.iMultisampleMode;
|
|
|
|
D3D::drawShadedTexQuad(
|
|
|
|
read_texture,
|
|
|
|
&sourcerect,
|
|
|
|
Renderer::GetFullTargetWidth() ,
|
|
|
|
Renderer::GetFullTargetHeight(),
|
|
|
|
PixelShaderCache::GetColorCopyProgram(SSAAMode),
|
|
|
|
(SSAAMode != 0)? VertexShaderCache::GetFSAAVertexShader() : VertexShaderCache::GetSimpleVertexShader());
|
|
|
|
|
|
|
|
|
|
|
|
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
|
|
|
D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER);
|
|
|
|
D3D::SetTexture(0,NULL);
|
|
|
|
D3D::dev->SetRenderTarget(0, GetEFBColorRTSurface());
|
|
|
|
D3D::dev->SetDepthStencilSurface(GetEFBDepthRTSurface());
|
|
|
|
Renderer::RestoreAPIState();
|
|
|
|
Rendersurf->Release();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
|
|
{
|
|
|
|
xfbCount = 1;
|
|
|
|
|
|
|
|
m_realXFBSource.texWidth = fbWidth;
|
|
|
|
m_realXFBSource.texHeight = fbHeight;
|
|
|
|
|
|
|
|
m_realXFBSource.srcAddr = xfbAddr;
|
|
|
|
m_realXFBSource.srcWidth = fbWidth;
|
|
|
|
m_realXFBSource.srcHeight = fbHeight;
|
|
|
|
|
|
|
|
if (!m_realXFBSource.texture)
|
|
|
|
{
|
|
|
|
D3D::dev->CreateTexture(fbWidth, fbHeight, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
|
|
D3DPOOL_DEFAULT, &m_realXFBSource.texture, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode YUYV data from GameCube RAM
|
|
|
|
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture);
|
|
|
|
|
|
|
|
m_overlappingXFBArray[0] = &m_realXFBSource;
|
|
|
|
|
|
|
|
return &m_overlappingXFBArray[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
const XFBSource** FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
|
|
{
|
|
|
|
xfbCount = 0;
|
|
|
|
|
|
|
|
if (m_virtualXFBList.size() == 0)
|
|
|
|
{
|
|
|
|
// No Virtual XFBs available.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 srcLower = xfbAddr;
|
|
|
|
u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight;
|
|
|
|
|
|
|
|
VirtualXFBListType::iterator it;
|
|
|
|
for (it = m_virtualXFBList.end(); it != m_virtualXFBList.begin();)
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
|
|
|
|
u32 dstLower = it->xfbAddr;
|
|
|
|
u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
|
|
|
|
|
|
|
|
if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
|
|
|
|
{
|
|
|
|
m_overlappingXFBArray[xfbCount] = &(it->xfbSource);
|
|
|
|
xfbCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &m_overlappingXFBArray[0];
|
|
|
|
}
|