Jordan Woyak 194493cc04 Some work on merging the video plugins: Added a new plugin to the solution(shouldn't build by default) which combines the DX9, DX11, and OGL plugins with their common code merged (and some things temporarily removed). In it's current state the plugin is hardly usable. Perhaps someone with knowledge of the video plugins will be able to fix the things I have broken more easily than me(or point me in the right direction). I will continue to work on it as well.
Main Issues:
DX11 is functional with a ~2MB/s mem leak.
OpenGL/DirectX9 have a black display while game runs. (DirectX 9 flashes good display on emulation stop)
Too many virtual function calls. (once everything is working, I will work on removing them)
Won't build on non-Windows in its current state. (mainly EmuWindow will need changes for Linux/OS X)
Probably other stuff.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6219 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-09-20 21:45:47 +00:00

391 lines
10 KiB
C++

#include <math.h>
#include "Common.h"
#include "Timer.h"
#include "Render.h"
#include "BPMemory.h"
#include "Atomic.h"
#include "VideoConfig.h"
#include "FramebufferManager.h"
#include "Fifo.h"
#include "VertexShaderManager.h"
#include "DLCache.h"
#include "OnScreenDisplay.h"
#include "Statistics.h"
#include "Renderer.h"
#include "Main.h"
int RendererBase::s_target_width;
int RendererBase::s_target_height;
int RendererBase::s_Fulltarget_width;
int RendererBase::s_Fulltarget_height;
int RendererBase::s_backbuffer_width;
int RendererBase::s_backbuffer_height;
int RendererBase::s_XFB_width;
int RendererBase::s_XFB_height;
float RendererBase::xScale;
float RendererBase::yScale;
int RendererBase::s_fps;
u32 RendererBase::s_blendMode;
bool RendererBase::XFBWrited;
float RendererBase::EFBxScale;
float RendererBase::EFByScale;
volatile u32 RendererBase::s_swapRequested;
//void VideoConfig::UpdateProjectionHack()
//{
// return;
// //::UpdateProjectionHack(g_Config.iPhackvalue);
//}
RendererBase::RendererBase()
{
UpdateActiveConfig();
s_blendMode = 0;
s_XFB_width = MAX_XFB_WIDTH;
s_XFB_height = MAX_XFB_HEIGHT;
}
// can maybe reuse this func in Renderer::Swap to eliminate redundant code
void RendererBase::FramebufferSize(int w, int h)
{
TargetRectangle dst_rect;
ComputeDrawRectangle(w, h, false, &dst_rect);
xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width;
yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height;
// TODO: why these, prolly can remove them
const int s_LastAA = g_ActiveConfig.iMultisampleMode;
const int s_LastEFBScale = g_ActiveConfig.iEFBScale;
switch (s_LastEFBScale)
{
case 0:
EFBxScale = xScale;
EFByScale = yScale;
break;
case 1:
EFBxScale = ceilf(xScale);
EFByScale = ceilf(yScale);
break;
default:
EFByScale = EFBxScale = (g_ActiveConfig.iEFBScale - 1);
break;
};
const float SupersampleCoeficient = s_LastAA + 1;
EFBxScale *= SupersampleCoeficient;
EFByScale *= SupersampleCoeficient;
s_target_width = (int)(EFB_WIDTH * EFBxScale);
s_target_height = (int)(EFB_HEIGHT * EFByScale);
// TODO: set anything else?
s_Fulltarget_width = s_target_width;
s_Fulltarget_height = s_target_height;
}
void UpdateViewport()
{
g_renderer->UpdateViewport();
}
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
{
RendererBase::RenderToXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
}
// whats this for?
bool IsD3D()
{
//PanicAlert("IsD3D!");
// TODO: temporary
return true;
}
void Renderer::RenderText(const char *pstr, int left, int top, u32 color)
{
}
void RendererBase::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
{
if (!fbWidth || !fbHeight)
return;
VideoFifo_CheckEFBAccess();
VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight);
XFBWrited = true;
// XXX: Without the VI, how would we know what kind of field this is? So
// just use progressive.
if (g_ActiveConfig.bUseXFB)
{
g_framebuffer_manager->CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
}
else
{
g_renderer->Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight, sourceRc);
Common::AtomicStoreRelease(s_swapRequested, FALSE);
}
}
TargetRectangle RendererBase::ConvertEFBRectangle(const EFBRectangle& rc)
{
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
TargetRectangle result;
result.left = (int)(rc.left * EFBxScale) + Xstride;
result.top = (int)(rc.top * EFByScale) + Ystride;
result.right = (int)(rc.right * EFBxScale) + Xstride;
result.bottom = (int)(rc.bottom * EFByScale) + Ystride;
return result;
}
bool RendererBase::SetScissorRect(EFBRectangle &rc)
{
int xoff = bpmem.scissorOffset.x * 2 - 342;
int yoff = bpmem.scissorOffset.y * 2 - 342;
rc.left = bpmem.scissorTL.x - xoff - 342;
rc.top = bpmem.scissorTL.y - yoff - 342;
rc.right = bpmem.scissorBR.x - xoff - 341;
rc.bottom = bpmem.scissorBR.y - yoff - 341;
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
rc.left = (int)(rc.left * EFBxScale);
rc.top = (int)(rc.top * EFByScale);
rc.right = (int)(rc.right * EFBxScale);
rc.bottom = (int)(rc.bottom * EFByScale);
if (rc.left < 0) rc.left = 0;
if (rc.right < 0) rc.right = 0;
if (rc.left > s_target_width) rc.left = s_target_width;
if (rc.right > s_target_width) rc.right = s_target_width;
if (rc.top < 0) rc.top = 0;
if (rc.bottom < 0) rc.bottom = 0;
if (rc.top > s_target_height) rc.top = s_target_height;
if (rc.bottom > s_target_height) rc.bottom = s_target_height;
rc.left += Xstride;
rc.top += Ystride;
rc.right += Xstride;
rc.bottom += Ystride;
if (rc.left > rc.right)
{
int temp = rc.right;
rc.right = rc.left;
rc.left = temp;
}
if (rc.top > rc.bottom)
{
int temp = rc.bottom;
rc.bottom = rc.top;
rc.top = temp;
}
return (rc.right >= rc.left && rc.bottom >= rc.top);
}
void RendererBase::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc)
{
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.bUseRealXFB) || !fbWidth || !fbHeight)
{
g_VideoInitialize.pCopiedToXFB(false);
return;
}
// this function is called after the XFB field is changed, not after
// EFB is copied to XFB. In this way, flickering is reduced in games
// and seems to also give more FPS in ZTP
if (field == FIELD_LOWER)
xfbAddr -= fbWidth * 2;
u32 xfbCount = 0;
const XFBSourceBase** xfbSourceList = g_framebuffer_manager->GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
{
g_VideoInitialize.pCopiedToXFB(false);
return;
}
g_renderer->ResetAPIState();
// prepare copying the XFBs to our backbuffer
TargetRectangle dst_rect;
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect);
g_renderer->PrepareXFBCopy(dst_rect);
if (g_ActiveConfig.bUseXFB)
{
const XFBSourceBase* xfbSource;
// draw each xfb source
for (u32 i = 0; i < xfbCount; ++i)
{
xfbSource = xfbSourceList[i];
TargetRectangle sourceRc;
//if (g_ActiveConfig.bAutoScale)
//{
// sourceRc = xfbSource->sourceRc;
//}
//else
//{
sourceRc.left = 0;
sourceRc.top = 0;
sourceRc.right = xfbSource->texWidth;
sourceRc.bottom = xfbSource->texHeight;
//}
MathUtil::Rectangle<float> drawRc;
if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
{
// use virtual xfb with offset
int xfbHeight = xfbSource->srcHeight;
int xfbWidth = xfbSource->srcWidth;
int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2);
drawRc.bottom = 1.0f - 2.0f * ((hOffset) / (float)fbHeight);
drawRc.top = 1.0f - 2.0f * ((hOffset + xfbHeight) / (float)fbHeight);
drawRc.left = -(xfbWidth / (float)fbWidth);
drawRc.right = (xfbWidth / (float)fbWidth);
if (!g_ActiveConfig.bAutoScale)
{
// scale draw area for a 1 to 1 pixel mapping with the draw target
float vScale = (float)fbHeight / (float)s_backbuffer_height;
float hScale = (float)fbWidth / (float)s_backbuffer_width;
drawRc.top *= vScale;
drawRc.bottom *= vScale;
drawRc.left *= hScale;
drawRc.right *= hScale;
}
}
else
{
drawRc.top = -1;
drawRc.bottom = 1;
drawRc.left = -1;
drawRc.right = 1;
}
g_renderer->Draw(xfbSource, sourceRc, drawRc, rc);
}
}
else
{
// TODO: organize drawRc stuff
MathUtil::Rectangle<float> drawRc;
drawRc.top = -1;
drawRc.bottom = 1;
drawRc.left = -1;
drawRc.right = 1;
const TargetRectangle targetRc = ConvertEFBRectangle(rc);
g_renderer->Draw(NULL, targetRc, drawRc, rc);
}
// done with drawing the game stuff, good moment to save a screenshot
// TODO: screenshot code
//
// finally present some information
// TODO: debug text, fps, etc...
//
OSD::DrawMessages();
g_renderer->EndFrame();
++frameCount;
DLCache::ProgressiveCleanup();
g_texture_cache->Cleanup();
// check for configuration changes
const int last_efbscale = g_ActiveConfig.iEFBScale;
//const int last_aa = g_ActiveConfig.iMultisampleMode;
UpdateActiveConfig();
bool window_resized = g_renderer->CheckForResize();
bool xfbchanged = false;
if (s_XFB_width != fbWidth || s_XFB_height != fbHeight)
{
xfbchanged = true;
s_XFB_width = fbWidth;
s_XFB_height = fbHeight;
if (s_XFB_width < 1) s_XFB_width = MAX_XFB_WIDTH;
if (s_XFB_width > MAX_XFB_WIDTH) s_XFB_width = MAX_XFB_WIDTH;
if (s_XFB_height < 1) s_XFB_height = MAX_XFB_HEIGHT;
if (s_XFB_height > MAX_XFB_HEIGHT) s_XFB_height = MAX_XFB_HEIGHT;
}
// update FPS counter
// TODO: make this better
static int fpscount = 0;
static unsigned long lasttime = 0;
if (Common::Timer::GetTimeMs() - lasttime >= 1000)
{
lasttime = Common::Timer::GetTimeMs();
s_fps = fpscount;
fpscount = 0;
}
if (XFBWrited)
++fpscount;
// set default viewport and scissor, for the clear to work correctly
stats.ResetFrame();
// done. Show our work ;)
g_renderer->Present();
// resize the back buffers NOW to avoid flickering when resizing windows
if (xfbchanged || window_resized || last_efbscale != g_ActiveConfig.iEFBScale)
{
g_renderer->GetBackBufferSize(&s_backbuffer_width, &s_backbuffer_height);
FramebufferSize(s_backbuffer_width, s_backbuffer_height);
g_renderer->RecreateFramebufferManger();
}
// begin next frame
g_renderer->RestoreAPIState();
g_renderer->BeginFrame();
g_renderer->UpdateViewport();
VertexShaderManager::SetViewportChanged();
g_VideoInitialize.pCopiedToXFB(XFBWrited || g_ActiveConfig.bUseRealXFB);
XFBWrited = false;
}