Files
dolphin/Source/Core/VideoBackends/Software/SWRenderer.cpp
T

208 lines
5.1 KiB
C++
Raw Normal View History

// Copyright 2009 Dolphin Emulator Project
2015-05-18 01:08:10 +02:00
// Licensed under GPLv2+
// Refer to the license.txt file included.
2010-06-09 01:37:08 +00:00
#include <algorithm>
#include <atomic>
2015-05-26 22:44:51 -05:00
#include <mutex>
2014-06-03 01:08:54 -04:00
#include <string>
2014-09-07 20:06:58 -05:00
#include "Common/CommonTypes.h"
2016-01-17 16:54:31 -05:00
#include "Common/FileUtil.h"
2014-06-03 01:08:54 -04:00
#include "Common/StringUtil.h"
2016-01-17 16:54:31 -05:00
#include "Common/Logging/Log.h"
2015-10-09 20:50:36 +02:00
#include "Core/ConfigManager.h"
#include "Core/HW/Memmap.h"
2015-10-09 20:50:36 +02:00
#include "VideoBackends/Software/EfbCopy.h"
2015-09-26 10:07:48 +02:00
#include "VideoBackends/Software/SWOGLWindow.h"
2014-02-17 05:18:15 -05:00
#include "VideoBackends/Software/SWRenderer.h"
2015-10-09 20:50:36 +02:00
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/Fifo.h"
2014-02-17 05:18:15 -05:00
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/OnScreenDisplay.h"
2015-10-09 20:50:36 +02:00
#include "VideoCommon/VideoConfig.h"
2013-11-24 00:52:17 +13:00
static u8 *s_xfbColorTexture[2];
2013-08-20 23:51:39 +12:00
static int s_currentColorTexture = 0;
2015-10-09 20:50:36 +02:00
SWRenderer::~SWRenderer()
2010-06-09 01:37:08 +00:00
{
2015-02-15 14:43:31 -05:00
delete[] s_xfbColorTexture[0];
delete[] s_xfbColorTexture[1];
2010-06-09 01:37:08 +00:00
}
2015-10-09 20:50:36 +02:00
void SWRenderer::Init()
2010-06-09 01:37:08 +00:00
{
2015-02-15 14:43:31 -05: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-24 00:52:17 +13:00
2013-08-20 23:51:39 +12:00
s_currentColorTexture = 0;
2010-06-09 01:37:08 +00:00
}
2015-10-09 20:50:36 +02:00
void SWRenderer::Shutdown()
{
2015-10-09 20:50:36 +02:00
g_Config.bRunning = false;
UpdateActiveConfig();
}
2015-10-09 20:50:36 +02:00
void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
2010-06-09 01:37:08 +00:00
{
2015-09-26 10:07:48 +02:00
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
2010-06-09 01:37:08 +00:00
}
2014-08-10 22:01:42 -04:00
u8* SWRenderer::GetNextColorTexture()
2014-08-10 21:18:38 -04:00
{
return s_xfbColorTexture[!s_currentColorTexture];
}
2014-08-10 22:01:42 -04:00
u8* SWRenderer::GetCurrentColorTexture()
2014-08-10 21:18:38 -04:00
{
2014-07-14 23:51:55 +12:00
return s_xfbColorTexture[s_currentColorTexture];
}
2014-08-10 22:01:42 -04:00
void SWRenderer::SwapColorTexture()
2014-08-10 21:18:38 -04:00
{
s_currentColorTexture = !s_currentColorTexture;
}
void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight)
2013-08-20 23:51:39 +12:00
{
2015-02-15 14:43:31 -05:00
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
2014-08-10 21:18:38 -04:00
{
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
return;
}
2013-08-20 23:51:39 +12:00
u32 offset = 0;
2014-08-10 22:01:42 -04:00
u8 *TexturePointer = GetNextColorTexture();
2013-08-20 23:51:39 +12:00
for (u16 y = 0; y < fbHeight; y++)
2013-08-20 23:51:39 +12:00
{
for (u16 x = 0; x < fbWidth; x+=2)
2013-08-20 23:51:39 +12:00
{
// We do this one color sample (aka 2 RGB pixles) at a time
int Y1 = xfb[x].Y - 16;
2015-02-15 14:43:31 -05:00
int Y2 = xfb[x + 1].Y - 16;
2013-08-20 23:51:39 +12:00
int U = int(xfb[x].UV) - 128;
2015-02-15 14:43:31 -05:00
int V = int(xfb[x + 1].UV) - 128;
2013-08-20 23:51:39 +12:00
// We do the inverse BT.601 conversion for YCbCr to RGB
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
2014-07-15 00:42:33 +12:00
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);
2013-08-20 23:51:39 +12:00
TexturePointer[offset++] = 255;
2014-07-15 00:42:33 +12:00
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);
2013-08-20 23:51:39 +12:00
TexturePointer[offset++] = 255;
}
xfb += fbWidth;
2013-08-20 23:51:39 +12:00
}
2014-08-10 22:01:42 -04:00
SwapColorTexture();
2013-08-20 23:51:39 +12:00
}
// Called on the GPU thread
2015-10-09 20:50:36 +02:00
void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma)
2013-08-20 23:51:39 +12:00
{
if (!Fifo::WillSkipCurrentFrame())
{
2015-10-09 20:50:36 +02:00
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);
2012-12-26 10:33:45 -06:00
DrawDebugText();
2010-06-09 01:37:08 +00:00
2015-09-26 10:07:48 +02:00
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
2015-10-09 20:50:36 +02:00
UpdateActiveConfig();
}
u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
{
u32 value = 0;
switch (type)
{
case PEEK_Z:
{
value = EfbInterface::GetDepth(x, y);
break;
}
case PEEK_COLOR:
{
u32 color = 0;
EfbInterface::GetColor(x, y, (u8*)&color);
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
break;
}
default:
break;
}
return value;
}
u16 SWRenderer::BBoxRead(int index)
{
return BoundingBox::coords[index];
}
void SWRenderer::BBoxWrite(int index, u16 value)
{
BoundingBox::coords[index] = value;
}
TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc)
{
TargetRectangle result;
result.left = rc.left;
result.top = rc.top;
result.right = rc.right;
result.bottom = rc.bottom;
return result;
}
void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
{
EfbCopy::ClearEfb();
2010-06-09 01:37:08 +00:00
}