| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2009 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:29:41 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 11:20:20 -05:00
										 |  |  | #include "VideoBackends/Software/SWRenderer.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-02 22:47:04 -04:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2015-05-14 12:33:19 -04:00
										 |  |  | #include <atomic>
 | 
					
						
							| 
									
										
										
										
											2015-05-26 22:44:51 -05:00
										 |  |  | #include <mutex>
 | 
					
						
							| 
									
										
										
										
											2014-06-03 01:08:54 -04:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2014-05-02 22:47:04 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-17 16:54:31 -05:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-19 04:40:00 +12:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "Core/HW/Memmap.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-19 04:40:00 +12:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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"
 | 
					
						
							| 
									
										
										
										
											2015-09-19 04:40:00 +12:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoCommon/BoundingBox.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "VideoCommon/OnScreenDisplay.h"
 | 
					
						
							| 
									
										
										
										
											2017-01-23 11:20:20 -05:00
										 |  |  | #include "VideoCommon/VideoBackendBase.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoCommon/VideoConfig.h"
 | 
					
						
							| 
									
										
										
										
											2013-04-13 00:48:53 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_currentColorTexture = 0; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | void SWRenderer::Shutdown() | 
					
						
							| 
									
										
										
										
											2013-11-15 22:07:08 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   g_Config.bRunning = false; | 
					
						
							|  |  |  |   UpdateActiveConfig(); | 
					
						
							| 
									
										
										
										
											2013-11-15 22:07:08 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return s_xfbColorTexture[!s_currentColorTexture]; | 
					
						
							| 
									
										
										
										
											2013-11-23 20:04:37 +13:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-10 22:01:42 -04:00
										 |  |  | u8* SWRenderer::GetCurrentColorTexture() | 
					
						
							| 
									
										
										
										
											2014-08-10 21:18:38 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return s_xfbColorTexture[s_currentColorTexture]; | 
					
						
							| 
									
										
										
										
											2014-07-14 23:51:55 +12:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-10 22:01:42 -04:00
										 |  |  | void SWRenderer::SwapColorTexture() | 
					
						
							| 
									
										
										
										
											2014-08-10 21:18:38 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_currentColorTexture = !s_currentColorTexture; | 
					
						
							| 
									
										
										
										
											2013-11-23 20:04:37 +13:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight) | 
					
						
							| 
									
										
										
										
											2013-08-20 23:51:39 +12:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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 23:51:39 +12:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Called on the GPU thread
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, | 
					
						
							| 
									
										
										
										
											2016-10-08 12:56:28 +02:00
										 |  |  |                           const EFBRectangle& rc, u64 ticks, float Gamma) | 
					
						
							| 
									
										
										
										
											2013-08-20 23:51:39 +12:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-07 19:55:47 -07:00
										 |  |  |   if (g_ActiveConfig.bUseXFB) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-07 19:55:47 -07:00
										 |  |  |     EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr); | 
					
						
							|  |  |  |     UpdateColorTexture(xfb, fbWidth, fbHeight); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-07 19:55:47 -07:00
										 |  |  |   // Save screenshot
 | 
					
						
							| 
									
										
										
										
											2016-10-10 09:49:13 +02:00
										 |  |  |   if (IsFrameDumping()) | 
					
						
							| 
									
										
										
										
											2016-10-07 19:55:47 -07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-11-04 18:19:35 +01:00
										 |  |  |     AVIDump::Frame state = AVIDump::FetchState(ticks); | 
					
						
							|  |  |  |     DumpFrameData(GetCurrentColorTexture(), fbWidth, fbHeight, fbWidth * 4, state); | 
					
						
							| 
									
										
										
										
											2016-10-10 09:49:13 +02:00
										 |  |  |     FinishFrameData(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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 20:50:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 value = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (type) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |   case EFBAccessType::PeekZ: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |     value = EfbInterface::GetDepth(x, y); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |   case EFBAccessType::PeekColor: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-09-21 18:53:13 -04:00
										 |  |  |     const u32 color = EfbInterface::GetColor(x, y); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // rgba to argb
 | 
					
						
							|  |  |  |     value = (color >> 8) | (color & 0xff) << 24; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return value; | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u16 SWRenderer::BBoxRead(int index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return BoundingBox::coords[index]; | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SWRenderer::BBoxWrite(int index, u16 value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   BoundingBox::coords[index] = value; | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   TargetRectangle result; | 
					
						
							|  |  |  |   result.left = rc.left; | 
					
						
							|  |  |  |   result.top = rc.top; | 
					
						
							|  |  |  |   result.right = rc.right; | 
					
						
							|  |  |  |   result.bottom = rc.bottom; | 
					
						
							|  |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, | 
					
						
							|  |  |  |                              bool zEnable, u32 color, u32 z) | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EfbCopy::ClearEfb(); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } |