D3D: Basic EFB copy-to-texture support. Fixes star domes in SMG (but does not fix the pull star, need EFB reads for that) and some other things.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4188 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-09-03 21:56:08 +00:00
parent baede3a7f3
commit efc74c77a9
6 changed files with 75 additions and 43 deletions

View File

@ -110,20 +110,18 @@ inline float Memory_Read_Float(u32 _uAddress)
void HandleGLError(); void HandleGLError();
// This structure should only be used to represent a rectangle in OpenGL target
// coordinates, where the origin is at the lower left and the frame dimensions
// depend on the resolution settings. Use Renderer::ConvertEFBRectangle to
// convert an EFBRectangle to a TargetRectangle.
struct TargetRectangle : public MathUtil::Rectangle<int>
{};
// This structure should only be used to represent a rectangle in EFB // This structure should only be used to represent a rectangle in EFB
// coordinates, where the origin is at the upper left and the frame dimensions // coordinates, where the origin is at the upper left and the frame dimensions
// are 640 x 528. // are 640 x 528.
struct EFBRectangle : public MathUtil::Rectangle<int> struct EFBRectangle : public MathUtil::Rectangle<int>
{}; {};
// This structure should only be used to represent a rectangle in standard target
// coordinates, where the origin is at the lower left and the frame dimensions
// depend on the resolution settings. Use Renderer::ConvertEFBRectangle to
// convert an EFBRectangle to a TargetRectangle.
struct TargetRectangle : public MathUtil::Rectangle<int>
{};
#ifdef _WIN32 #ifdef _WIN32
#define PRIM_LOG(...) {DEBUG_LOG(VIDEO, __VA_ARGS__)} #define PRIM_LOG(...) {DEBUG_LOG(VIDEO, __VA_ARGS__)}

View File

@ -207,9 +207,7 @@ void SetColorMask(const BPCmd &bp)
void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 &copyfmt, const bool &scaleByHalf) void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 &copyfmt, const bool &scaleByHalf)
{ {
// TODO: Scale EFBRectangle correctly TextureCache::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
RECT rec = { rc.left, rc.top, rc.right, rc.bottom };
TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest << 5, &rec);
} }
void RenderToXFB(const BPCmd &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) void RenderToXFB(const BPCmd &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)

View File

@ -41,10 +41,8 @@
#include "debugger/debugger.h" #include "debugger/debugger.h"
static float m_x; static float m_targetWidth;
static float m_y; static float m_targetHeight;
static float m_width;
static float m_height;
static float xScale; static float xScale;
static float yScale; static float yScale;
@ -63,15 +61,11 @@ bool Renderer::Init()
D3D::Create(g_Config.iAdapter, EmuWindow::GetWnd(), g_Config.bFullscreen, g_Config.iFSResolution, g_Config.iMultisampleMode); D3D::Create(g_Config.iAdapter, EmuWindow::GetWnd(), g_Config.bFullscreen, g_Config.iFSResolution, g_Config.iMultisampleMode);
float width = (float)D3D::GetDisplayWidth(); m_targetWidth = (float)D3D::GetDisplayWidth();
float height = (float)D3D::GetDisplayHeight(); m_targetHeight = (float)D3D::GetDisplayHeight();
m_x = 0; xScale = m_targetWidth / (float)EFB_WIDTH;
m_y = 0; yScale = m_targetHeight / (float)EFB_HEIGHT;
m_width = width;
m_height = height;
xScale = m_width / (float)EFB_WIDTH;
yScale = m_height / (float)EFB_HEIGHT;
m_LastFrameDumped = false; m_LastFrameDumped = false;
m_AVIDumping = false; m_AVIDumping = false;
@ -129,11 +123,23 @@ void dumpMatrix(D3DXMATRIX &mtx)
} }
} }
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
{
TargetRectangle result;
result.left = (rc.left * m_targetWidth) / EFB_WIDTH;
result.top = (rc.top * m_targetHeight) / EFB_HEIGHT;
result.right = (rc.right * m_targetWidth) / EFB_WIDTH;
result.bottom = (rc.bottom * m_targetHeight) / EFB_HEIGHT;
return result;
}
void formatBufferDump(const char *in, char *out, int w, int h, int p) void formatBufferDump(const char *in, char *out, int w, int h, int p)
{ {
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++)
{
const char *line = in + (h - y - 1) * p; const char *line = in + (h - y - 1) * p;
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++)
{
memcpy(out, line, 3); memcpy(out, line, 3);
out += 3; out += 3;
line += 4; line += 4;
@ -250,16 +256,16 @@ void Renderer::SwapBuffers()
D3DVIEWPORT9 vp; D3DVIEWPORT9 vp;
vp.X = 0; vp.X = 0;
vp.Y = 0; vp.Y = 0;
vp.Width = (DWORD)m_width; vp.Width = (DWORD)m_targetWidth;
vp.Height = (DWORD)m_height; vp.Height = (DWORD)m_targetHeight;
vp.MinZ = 0; vp.MinZ = 0;
vp.MaxZ = 1.0f; vp.MaxZ = 1.0f;
D3D::dev->SetViewport(&vp); D3D::dev->SetViewport(&vp);
RECT rc; RECT rc;
rc.left = 0; rc.left = 0;
rc.top = 0; rc.top = 0;
rc.right = (LONG)m_width; rc.right = (LONG)m_targetWidth;
rc.bottom = (LONG)m_height; rc.bottom = (LONG)m_targetHeight;
D3D::dev->SetScissorRect(&rc); D3D::dev->SetScissorRect(&rc);
D3D::dev->SetRenderState(D3DRS_SCISSORTESTENABLE, false); D3D::dev->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
@ -315,8 +321,8 @@ void Renderer::SetColorMask()
D3D::SetRenderState(D3DRS_COLORWRITEENABLE, write); D3D::SetRenderState(D3DRS_COLORWRITEENABLE, write);
} }
// mtx.m[0][3] = pMatrix[1]; // -0.5f/m_width; <-- fix d3d pixel center? // mtx.m[0][3] = pMatrix[1]; // -0.5f/m_targetWidth; <-- fix d3d pixel center?
// mtx.m[1][3] = pMatrix[3]; // +0.5f/m_height; <-- fix d3d pixel center? // mtx.m[1][3] = pMatrix[3]; // +0.5f/m_targetHeight; <-- fix d3d pixel center?
// Called from VertexShaderManager // Called from VertexShaderManager
void UpdateViewport() void UpdateViewport()

View File

@ -248,9 +248,16 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width,
return &entry; return &entry;
} }
// EXTREMELY incomplete.
void TextureCache::CopyEFBToRenderTarget(u32 address, RECT *source) void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect)
{ {
int efb_w = source_rect.GetWidth();
int efb_h = source_rect.GetHeight();
int mult = bScaleByHalf ? 2 : 1;
int tex_w = (abs(source_rect.GetWidth()) / mult);
int tex_h = (abs(source_rect.GetHeight()) / mult);
TexCache::iterator iter; TexCache::iterator iter;
LPDIRECT3DTEXTURE9 tex; LPDIRECT3DTEXTURE9 tex;
iter = textures.find(address); iter = textures.find(address);
@ -259,27 +266,50 @@ void TextureCache::CopyEFBToRenderTarget(u32 address, RECT *source)
if (!iter->second.isRenderTarget) if (!iter->second.isRenderTarget)
{ {
ERROR_LOG(VIDEO, "Using non-rendertarget texture as render target!!! WTF?", FALSE); ERROR_LOG(VIDEO, "Using non-rendertarget texture as render target!!! WTF?", FALSE);
//TODO: remove it and recreate it as a render target // Remove it and recreate it as a render target
} iter->second.texture->Release();
tex = iter->second.texture; iter->second.texture = 0;
iter->second.frameCount = frameCount; textures.erase(iter);
} }
else else
{
tex = iter->second.texture;
iter->second.frameCount = frameCount;
goto have_texture;
}
}
{ {
TCacheEntry entry; TCacheEntry entry;
entry.isRenderTarget = true; entry.isRenderTarget = true;
entry.hash = 0; entry.hash = 0;
entry.hashoffset = 0; entry.hashoffset = 0;
entry.frameCount = frameCount; entry.frameCount = frameCount;
entry.w = tex_w;
entry.h = tex_h;
// TODO(ector): infer this size in some sensible way // TODO(ector): infer this size in some sensible way
D3D::dev->CreateTexture(512, 512, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &entry.texture, 0); D3D::dev->CreateTexture(tex_w, tex_h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &entry.texture, 0);
textures[address] = entry; textures[address] = entry;
tex = entry.texture; tex = entry.texture;
} }
LPDIRECT3DSURFACE9 srcSurface,destSurface; have_texture:
tex->GetSurfaceLevel(0,&destSurface); TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect);
RECT source_rc;
source_rc.left = targetSource.left;
source_rc.top = targetSource.top;
source_rc.right = targetSource.right;
source_rc.bottom = targetSource.bottom;
RECT dest_rc;
dest_rc.left = 0;
dest_rc.top = 0;
dest_rc.right = tex_w;
dest_rc.bottom = tex_h;
LPDIRECT3DSURFACE9 srcSurface, destSurface;
tex->GetSurfaceLevel(0, &destSurface);
srcSurface = D3D::GetBackBufferSurface(); srcSurface = D3D::GetBackBufferSurface();
D3D::dev->StretchRect(srcSurface,source,destSurface,0,D3DTEXF_NONE); D3D::dev->StretchRect(srcSurface, &source_rc, destSurface, &dest_rc, D3DTEXF_LINEAR);
destSurface->Release(); destSurface->Release();
} }

View File

@ -22,6 +22,7 @@
#include <map> #include <map>
#include "D3DBase.h" #include "D3DBase.h"
#include "VideoCommon.h"
#include "BPMemory.h" #include "BPMemory.h"
class TextureCache class TextureCache
@ -62,7 +63,7 @@ public:
static void Shutdown(); static void Shutdown();
static void Invalidate(bool shutdown); static void Invalidate(bool shutdown);
static TCacheEntry *Load(int stage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt); static TCacheEntry *Load(int stage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt);
static void CopyEFBToRenderTarget(u32 address, RECT *source); static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect);
}; };
#endif #endif

View File

@ -548,7 +548,6 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
} }
} }
if (!bIsInit || !entry.isRenderTarget) if (!bIsInit || !entry.isRenderTarget)
{ {
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);