2015-05-24 04:55:12 +00:00
|
|
|
// Copyright 2009 Dolphin Emulator Project
|
2015-05-17 23:08:10 +00:00
|
|
|
// Licensed under GPLv2+
|
2013-04-18 03:29:41 +00:00
|
|
|
// Refer to the license.txt file included.
|
2010-06-09 01:37:08 +00:00
|
|
|
|
2014-05-03 02:47:04 +00:00
|
|
|
#include <algorithm>
|
2015-05-14 16:33:19 +00:00
|
|
|
#include <atomic>
|
2015-05-27 03:44:51 +00:00
|
|
|
#include <mutex>
|
2014-06-03 05:08:54 +00:00
|
|
|
#include <string>
|
2014-05-03 02:47:04 +00:00
|
|
|
|
2014-09-08 01:06:58 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2016-01-17 21:54:31 +00:00
|
|
|
#include "Common/FileUtil.h"
|
|
|
|
#include "Common/Logging/Log.h"
|
2016-06-24 08:43:46 +00:00
|
|
|
#include "Common/StringUtil.h"
|
2015-09-18 16:40:00 +00:00
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
#include "Core/ConfigManager.h"
|
|
|
|
#include "Core/HW/Memmap.h"
|
2015-09-18 16:40:00 +00:00
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
#include "VideoBackends/Software/EfbCopy.h"
|
2015-09-26 08:07:48 +00:00
|
|
|
#include "VideoBackends/Software/SWOGLWindow.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoBackends/Software/SWRenderer.h"
|
2015-09-18 16:40:00 +00:00
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
#include "VideoCommon/BoundingBox.h"
|
|
|
|
#include "VideoCommon/Fifo.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoCommon/ImageWrite.h"
|
|
|
|
#include "VideoCommon/OnScreenDisplay.h"
|
2015-10-09 18:50:36 +00:00
|
|
|
#include "VideoCommon/VideoConfig.h"
|
2013-04-13 05:48:53 +00:00
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
static u8* s_xfbColorTexture[2];
|
2013-08-20 11:51:39 +00:00
|
|
|
static int s_currentColorTexture = 0;
|
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
SWRenderer::~SWRenderer()
|
2010-06-09 01:37:08 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
delete[] s_xfbColorTexture[0];
|
|
|
|
delete[] s_xfbColorTexture[1];
|
2010-06-09 01:37:08 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
void SWRenderer::Init()
|
2010-06-09 01:37:08 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
|
|
|
s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
2013-11-23 11:52:17 +00:00
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
s_currentColorTexture = 0;
|
2010-06-09 01:37:08 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
void SWRenderer::Shutdown()
|
2013-11-16 04:07:08 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
g_Config.bRunning = false;
|
|
|
|
UpdateActiveConfig();
|
2013-11-16 04:07:08 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 18:50:36 +00:00
|
|
|
void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
|
2010-06-09 01:37:08 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
2010-06-09 01:37:08 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 02:01:42 +00:00
|
|
|
u8* SWRenderer::GetNextColorTexture()
|
2014-08-11 01:18:38 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
return s_xfbColorTexture[!s_currentColorTexture];
|
2013-11-23 07:04:37 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 02:01:42 +00:00
|
|
|
u8* SWRenderer::GetCurrentColorTexture()
|
2014-08-11 01:18:38 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
return s_xfbColorTexture[s_currentColorTexture];
|
2014-07-14 11:51:55 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 02:01:42 +00:00
|
|
|
void SWRenderer::SwapColorTexture()
|
2014-08-11 01:18:38 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
s_currentColorTexture = !s_currentColorTexture;
|
2013-11-23 07:04:37 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight)
|
2013-08-20 11:51:39 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
|
|
|
|
{
|
|
|
|
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 offset = 0;
|
|
|
|
u8* TexturePointer = GetNextColorTexture();
|
|
|
|
|
|
|
|
for (u16 y = 0; y < fbHeight; y++)
|
|
|
|
{
|
|
|
|
for (u16 x = 0; x < fbWidth; x += 2)
|
|
|
|
{
|
|
|
|
// We do this one color sample (aka 2 RGB pixles) at a time
|
|
|
|
int Y1 = xfb[x].Y - 16;
|
|
|
|
int Y2 = xfb[x + 1].Y - 16;
|
|
|
|
int U = int(xfb[x].UV) - 128;
|
|
|
|
int V = int(xfb[x + 1].UV) - 128;
|
|
|
|
|
|
|
|
// We do the inverse BT.601 conversion for YCbCr to RGB
|
|
|
|
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
|
|
|
|
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255);
|
|
|
|
TexturePointer[offset++] =
|
|
|
|
MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255);
|
|
|
|
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255);
|
|
|
|
TexturePointer[offset++] = 255;
|
|
|
|
|
|
|
|
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255);
|
|
|
|
TexturePointer[offset++] =
|
|
|
|
MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255);
|
|
|
|
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255);
|
|
|
|
TexturePointer[offset++] = 255;
|
|
|
|
}
|
|
|
|
xfb += fbWidth;
|
|
|
|
}
|
|
|
|
SwapColorTexture();
|
2013-08-20 11:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Called on the GPU thread
|
2016-06-24 08:43:46 +00:00
|
|
|
void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|
|
|
const EFBRectangle& rc, float Gamma)
|
2013-08-20 11:51:39 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
if (!Fifo::WillSkipCurrentFrame())
|
|
|
|
{
|
|
|
|
if (g_ActiveConfig.bUseXFB)
|
|
|
|
{
|
|
|
|
EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr);
|
|
|
|
UpdateColorTexture(xfb, fbWidth, fbHeight);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save screenshot
|
|
|
|
if (s_bScreenshot)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
|
|
|
|
|
|
|
|
if (TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight,
|
|
|
|
false))
|
|
|
|
OSD::AddMessage("Screenshot saved to " + s_sScreenshotName);
|
|
|
|
|
|
|
|
// Reset settings
|
|
|
|
s_sScreenshotName.clear();
|
|
|
|
s_bScreenshot = false;
|
|
|
|
s_screenshotCompleted.Set();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SConfig::GetInstance().m_DumpFrames)
|
|
|
|
{
|
|
|
|
static int frame_index = 0;
|
|
|
|
TextureToPng(GetCurrentColorTexture(), fbWidth * 4,
|
|
|
|
StringFromFormat("%sframe%i_color.png",
|
|
|
|
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), frame_index),
|
|
|
|
fbWidth, fbHeight, true);
|
|
|
|
frame_index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
|
|
|
|
|
|
|
|
DrawDebugText();
|
|
|
|
|
|
|
|
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
|
|
|
|
|
|
|
|
UpdateActiveConfig();
|
|
|
|
|
|
|
|
// virtual XFB is not supported
|
|
|
|
if (g_ActiveConfig.bUseXFB)
|
|
|
|
g_ActiveConfig.bUseRealXFB = true;
|
2015-10-09 18:50:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
u32 value = 0;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case PEEK_Z:
|
|
|
|
{
|
|
|
|
value = EfbInterface::GetDepth(x, y);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PEEK_COLOR:
|
|
|
|
{
|
2016-09-21 22:53:13 +00:00
|
|
|
const u32 color = EfbInterface::GetColor(x, y);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
// rgba to argb
|
|
|
|
value = (color >> 8) | (color & 0xff) << 24;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
2015-10-09 18:50:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u16 SWRenderer::BBoxRead(int index)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
return BoundingBox::coords[index];
|
2015-10-09 18:50:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SWRenderer::BBoxWrite(int index, u16 value)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
BoundingBox::coords[index] = value;
|
2015-10-09 18:50:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
TargetRectangle result;
|
|
|
|
result.left = rc.left;
|
|
|
|
result.top = rc.top;
|
|
|
|
result.right = rc.right;
|
|
|
|
result.bottom = rc.bottom;
|
|
|
|
return result;
|
2015-10-09 18:50:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable,
|
|
|
|
bool zEnable, u32 color, u32 z)
|
2015-10-09 18:50:36 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
EfbCopy::ClearEfb();
|
2010-06-09 01:37:08 +00:00
|
|
|
}
|