dolphin/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp

247 lines
No EOL
8.7 KiB
C++

// 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"
#include "VideoConfig.h"
namespace FBManager
{
static LPDIRECT3DTEXTURE9 s_efb_color_texture;
static LPDIRECT3DTEXTURE9 s_efb_colorBuffer_texture;
static LPDIRECT3DTEXTURE9 s_efb_depth_texture;
static LPDIRECT3DTEXTURE9 s_efb_depthBuffer_texture;
static LPDIRECT3DSURFACE9 s_efb_color_surface;
static LPDIRECT3DSURFACE9 s_efb_depth_surface;
static LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer;
static LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer;
static LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer;
static LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer;
static D3DFORMAT s_efb_color_surface_Format;
static D3DFORMAT s_efb_depth_surface_Format;
#undef CHECK
#define CHECK(hr,Message) //if (FAILED(hr)) { PanicAlert(__FUNCTION__ " FAIL: %s" ,Message); }
LPDIRECT3DSURFACE9 GetEFBColorRTSurface() { return s_efb_color_surface; }
LPDIRECT3DSURFACE9 GetEFBDepthRTSurface() { return s_efb_depth_surface; }
LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface() { return s_efb_color_OffScreenReadBuffer; }
LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface() { return s_efb_depth_OffScreenReadBuffer; }
LPDIRECT3DSURFACE9 GetEFBColorReadSurface() { return s_efb_color_ReadBuffer; }
LPDIRECT3DSURFACE9 GetEFBDepthReadSurface() { return s_efb_depth_ReadBuffer; }
D3DFORMAT GetEFBDepthRTSurfaceFormat(){return s_efb_depth_surface_Format;}
D3DFORMAT GetEFBColorRTSurfaceFormat(){return s_efb_color_surface_Format;}
LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc)
{
return s_efb_color_texture;
}
LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle &sourceRc)
{
// Depth textures not supported under DX9. We're gonna fake this
// with a secondary render target later.
return s_efb_depth_texture;
}
void Create()
{
// Simplest possible setup to start with.
int target_width = Renderer::GetTargetWidth();
int target_height = Renderer::GetTargetHeight();
s_efb_color_surface_Format = D3DFMT_A8R8G8B8;
//get the framebuffer texture
HRESULT hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &s_efb_color_texture, NULL);
CHECK(hr,"Create Color Texture");
//get the Surface
hr = s_efb_color_texture->GetSurfaceLevel(0, &s_efb_color_surface);
CHECK(hr,"Get Color Surface");
//create a one pixel texture to work as a buffer for peeking
hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &s_efb_colorBuffer_texture, NULL);
if (!FAILED(hr))
{
//get the surface for the peeking texture
hr = s_efb_colorBuffer_texture->GetSurfaceLevel(0, &s_efb_color_ReadBuffer);
CHECK(hr,"Get Color Pixel Surface");
//create an offscreen surface that we can lock to retrieve the data
hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreenReadBuffer, NULL );
CHECK(hr,"Create Color offScreen Surface");
}
//Select Zbuffer format supported by hadware.
if (g_ActiveConfig.bEFBAccessEnable)
{
//depth format in prefered order
D3DFORMAT *DepthTexFormats = new D3DFORMAT[7];
DepthTexFormats[0] = (D3DFORMAT)MAKEFOURCC('D','F','2','4');
DepthTexFormats[1] = (D3DFORMAT)MAKEFOURCC('I','N','T','Z');
DepthTexFormats[2] = (D3DFORMAT)MAKEFOURCC('R','A','W','Z');
DepthTexFormats[3] = (D3DFORMAT)MAKEFOURCC('D','F','1','6');
DepthTexFormats[4] = D3DFMT_D32F_LOCKABLE;
DepthTexFormats[5] = D3DFMT_D16_LOCKABLE;
DepthTexFormats[6] = D3DFMT_D24X8;
for (int i = 0;i<4;i++)
{
s_efb_depth_surface_Format = DepthTexFormats[i];
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,"Create Depth Texture");
if (!FAILED(hr))
{
//we found a dept texture suported by hardware so get the surface to draw to
hr = s_efb_depth_texture->GetSurfaceLevel(0, &s_efb_depth_surface);
CHECK(hr,"Get Depth Surface");
//create a buffer texture for peeking
hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format,
D3DPOOL_DEFAULT, &s_efb_depthBuffer_texture, NULL);
CHECK(hr,"Create Depth Pixel Texture");
if (!FAILED(hr))
{
//texture create correctly so get the surface
hr = s_efb_depthBuffer_texture->GetSurfaceLevel(0, &s_efb_depth_ReadBuffer);
CHECK(hr,"Get Depth Pixel Surface");
// create an ofscren surface to grab the data
hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, s_efb_depth_surface_Format, D3DPOOL_SYSTEMMEM, &s_efb_depth_OffScreenReadBuffer, NULL );
CHECK(hr,"Create Depth offscreen Surface");
if (FAILED(hr))
{
//no depth in system mem so try vista path to grab depth data
//create a offscreen lockeable surface
hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, D3DFMT_D32F_LOCKABLE, D3DPOOL_DEFAULT, &s_efb_depth_OffScreenReadBuffer, NULL );
CHECK(hr, "Create Depth D3DFMT_D32F_LOCKABLE offscreen Surface");
if (s_efb_depth_ReadBuffer)
s_efb_depth_ReadBuffer->Release();
//this is ugly but is a fast way to test wich path to proceed for peeking
s_efb_depth_ReadBuffer = s_efb_depth_OffScreenReadBuffer;
s_efb_depth_surface_Format = D3DFMT_D32F_LOCKABLE;
}
}
}
if (!FAILED(hr))
{
//so far so god, texture depth works so return
delete [] DepthTexFormats;
return;
}
else
{
//no depth texture... cleanup
if(s_efb_depth_ReadBuffer)
s_efb_depth_ReadBuffer->Release();
s_efb_depth_ReadBuffer = NULL;
if(s_efb_depth_OffScreenReadBuffer)
s_efb_depth_OffScreenReadBuffer->Release();
if(s_efb_depth_surface)
s_efb_depth_surface->Release();
s_efb_depth_surface = NULL;
if(s_efb_depthBuffer_texture)
s_efb_depthBuffer_texture->Release();
s_efb_depthBuffer_texture=NULL;
if(s_efb_depth_texture)
s_efb_depth_texture->Release();
s_efb_depth_texture = NULL;
}
// no depth textures... try to create an lockable depth surface
for(int i = 4;i<7;i++)
{
s_efb_depth_surface_Format = DepthTexFormats[i];
hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, s_efb_depth_surface_Format,
D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL);
if (!FAILED(hr)) break;
}
s_efb_depth_ReadBuffer = s_efb_depth_surface;
CHECK(hr,"CreateDepthStencilSurface");
delete [] DepthTexFormats;
}
else
{
s_efb_depth_surface_Format = D3DFMT_D24X8;
hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, s_efb_depth_surface_Format,
D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL);
CHECK(hr,"CreateDepthStencilSurface");
}
}
void Destroy()
{
if(s_efb_depth_ReadBuffer)
s_efb_depth_ReadBuffer->Release();
s_efb_depth_ReadBuffer = NULL;
if(s_efb_depth_OffScreenReadBuffer)
s_efb_depth_OffScreenReadBuffer->Release();
if(s_efb_depth_surface)
s_efb_depth_surface->Release();
s_efb_depth_surface = NULL;
if(s_efb_depthBuffer_texture)
s_efb_depthBuffer_texture->Release();
s_efb_depthBuffer_texture=NULL;
if(s_efb_depth_texture)
s_efb_depth_texture->Release();
s_efb_depth_texture = NULL;
if(s_efb_color_OffScreenReadBuffer )
s_efb_color_OffScreenReadBuffer->Release();
s_efb_color_OffScreenReadBuffer = NULL;
if(s_efb_color_ReadBuffer )
s_efb_color_ReadBuffer->Release();
s_efb_color_ReadBuffer = NULL;
if(s_efb_color_surface)
s_efb_color_surface->Release();
s_efb_color_surface = NULL;
if(s_efb_colorBuffer_texture)
s_efb_colorBuffer_texture->Release();
s_efb_colorBuffer_texture = NULL;
if(s_efb_color_texture)
s_efb_color_texture->Release();
s_efb_color_texture = NULL;
}
} // namespace