| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "FramebufferManagerBase.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 02:21:26 +00:00
										 |  |  | #include "RenderBase.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | #include "VideoConfig.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FramebufferManagerBase *g_framebuffer_manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | XFBSourceBase *FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB mode
 | 
					
						
							|  |  |  | FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode
 | 
					
						
							|  |  |  | const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[MAX_VIRTUAL_XFB]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | unsigned int FramebufferManagerBase::s_last_xfb_width = 1; | 
					
						
							|  |  |  | unsigned int FramebufferManagerBase::s_last_xfb_height = 1; | 
					
						
							| 
									
										
										
										
											2012-09-28 23:48:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | FramebufferManagerBase::FramebufferManagerBase() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	m_realXFBSource = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// can't hurt
 | 
					
						
							|  |  |  | 	memset(m_overlappingXFBArray, 0, sizeof(m_overlappingXFBArray)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FramebufferManagerBase::~FramebufferManagerBase() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	VirtualXFBListType::iterator | 
					
						
							|  |  |  | 		it = m_virtualXFBList.begin(), | 
					
						
							|  |  |  | 		vlend = m_virtualXFBList.end(); | 
					
						
							|  |  |  | 	for (; it != vlend; ++it) | 
					
						
							|  |  |  | 		delete it->xfbSource; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_virtualXFBList.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	delete m_realXFBSource; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const XFBSourceBase* const* FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-24 09:21:54 -04:00
										 |  |  | 	if (!g_ActiveConfig.bUseXFB) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2011-03-19 00:21:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | 	if (g_ActiveConfig.bUseRealXFB) | 
					
						
							|  |  |  | 		return GetRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return GetVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	xfbCount = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!m_realXFBSource) | 
					
						
							|  |  |  | 		m_realXFBSource = g_framebuffer_manager->CreateXFBSource(fbWidth, fbHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_realXFBSource->srcAddr = xfbAddr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_realXFBSource->srcWidth = MAX_XFB_WIDTH; | 
					
						
							|  |  |  | 	m_realXFBSource->srcHeight = MAX_XFB_HEIGHT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_realXFBSource->texWidth = fbWidth; | 
					
						
							|  |  |  | 	m_realXFBSource->texHeight = fbHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: stuff only used by OGL... :/
 | 
					
						
							| 
									
										
										
										
											2013-03-19 21:51:12 -04:00
										 |  |  | 	// OpenGL texture coordinates originate at the lower left, which is why
 | 
					
						
							|  |  |  | 	// sourceRc.top = fbHeight and sourceRc.bottom = 0.
 | 
					
						
							|  |  |  | 	m_realXFBSource->sourceRc.left = 0; | 
					
						
							|  |  |  | 	m_realXFBSource->sourceRc.top = fbHeight; | 
					
						
							|  |  |  | 	m_realXFBSource->sourceRc.right = fbWidth; | 
					
						
							|  |  |  | 	m_realXFBSource->sourceRc.bottom = 0; | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Decode YUYV data from GameCube RAM
 | 
					
						
							|  |  |  | 	m_realXFBSource->DecodeToTexture(xfbAddr, fbWidth, fbHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_overlappingXFBArray[0] = m_realXFBSource; | 
					
						
							|  |  |  | 	return &m_overlappingXFBArray[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const XFBSourceBase* const* FramebufferManagerBase::GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	xfbCount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (m_virtualXFBList.empty())  // no Virtual XFBs available
 | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u32 srcLower = xfbAddr; | 
					
						
							|  |  |  | 	u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	VirtualXFBListType::reverse_iterator | 
					
						
							|  |  |  | 		it = m_virtualXFBList.rbegin(), | 
					
						
							|  |  |  | 		vlend = m_virtualXFBList.rend(); | 
					
						
							|  |  |  | 	for (; it != vlend; ++it) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		VirtualXFB* vxfb = &*it; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		u32 dstLower = vxfb->xfbAddr; | 
					
						
							|  |  |  | 		u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			m_overlappingXFBArray[xfbCount] = vxfb->xfbSource; | 
					
						
							|  |  |  | 			++xfbCount; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &m_overlappingXFBArray[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-27 03:18:01 +00:00
										 |  |  | void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (g_ActiveConfig.bUseRealXFB) | 
					
						
							| 
									
										
										
										
											2010-12-27 03:18:01 +00:00
										 |  |  | 		g_framebuffer_manager->CopyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc,Gamma); | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2010-12-27 03:18:01 +00:00
										 |  |  | 		CopyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc,Gamma); | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-27 03:18:01 +00:00
										 |  |  | void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	VirtualXFBListType::iterator vxfb = FindVirtualXFB(xfbAddr, fbWidth, fbHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (m_virtualXFBList.end() == vxfb) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (m_virtualXFBList.size() < MAX_VIRTUAL_XFB) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// create a new Virtual XFB and place it at the front of the list
 | 
					
						
							|  |  |  | 			VirtualXFB v; | 
					
						
							|  |  |  | 			memset(&v, 0, sizeof v); | 
					
						
							|  |  |  | 			m_virtualXFBList.push_front(v); | 
					
						
							|  |  |  | 			vxfb = m_virtualXFBList.begin(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Replace the last virtual XFB
 | 
					
						
							|  |  |  | 			--vxfb; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	//else // replace existing virtual XFB
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// move this Virtual XFB to the front of the list.
 | 
					
						
							|  |  |  | 	if (m_virtualXFBList.begin() != vxfb) | 
					
						
							|  |  |  | 		m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, vxfb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unsigned int target_width, target_height; | 
					
						
							|  |  |  | 	g_framebuffer_manager->GetTargetSize(&target_width, &target_height, sourceRc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// recreate if needed
 | 
					
						
							|  |  |  | 	if (vxfb->xfbSource && (vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		//delete vxfb->xfbSource;
 | 
					
						
							|  |  |  | 		//vxfb->xfbSource = NULL;
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!vxfb->xfbSource) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		vxfb->xfbSource = g_framebuffer_manager->CreateXFBSource(target_width, target_height); | 
					
						
							|  |  |  | 		vxfb->xfbSource->texWidth = target_width; | 
					
						
							|  |  |  | 		vxfb->xfbSource->texHeight = target_height; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vxfb->xfbSource->srcAddr = vxfb->xfbAddr = xfbAddr; | 
					
						
							|  |  |  | 	vxfb->xfbSource->srcWidth = vxfb->xfbWidth = fbWidth; | 
					
						
							|  |  |  | 	vxfb->xfbSource->srcHeight = vxfb->xfbHeight = fbHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 02:21:26 +00:00
										 |  |  | 	vxfb->xfbSource->sourceRc = g_renderer->ConvertEFBRectangle(sourceRc); | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// keep stale XFB data from being used
 | 
					
						
							|  |  |  | 	ReplaceVirtualXFB(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Copy EFB data to XFB and restore render target again
 | 
					
						
							| 
									
										
										
										
											2010-12-27 03:18:01 +00:00
										 |  |  | 	vxfb->xfbSource->CopyEFB(Gamma); | 
					
						
							| 
									
										
										
										
											2010-11-14 23:56:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FramebufferManagerBase::VirtualXFBListType::iterator FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const u32 srcLower = xfbAddr; | 
					
						
							|  |  |  | 	const u32 srcUpper = xfbAddr + 2 * width * height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	VirtualXFBListType::iterator it = m_virtualXFBList.begin(); | 
					
						
							|  |  |  | 	for (; it != m_virtualXFBList.end(); ++it) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		const u32 dstLower = it->xfbAddr; | 
					
						
							|  |  |  | 		const u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (dstLower >= srcLower && dstUpper <= srcUpper) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return it; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FramebufferManagerBase::ReplaceVirtualXFB() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	VirtualXFBListType::iterator it = m_virtualXFBList.begin(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const s32 srcLower = it->xfbAddr; | 
					
						
							|  |  |  | 	const s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; | 
					
						
							|  |  |  | 	const s32 lineSize = 2 * it->xfbWidth; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	++it; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (; it != m_virtualXFBList.end(); ++it) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		s32 dstLower = it->xfbAddr; | 
					
						
							|  |  |  | 		s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (dstLower >= srcLower && dstUpper <= srcUpper) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Invalidate the data
 | 
					
						
							|  |  |  | 			it->xfbAddr = 0; | 
					
						
							|  |  |  | 			it->xfbHeight = 0; | 
					
						
							|  |  |  | 			it->xfbWidth = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			s32 upperOverlap = (srcUpper - dstLower) / lineSize; | 
					
						
							|  |  |  | 			s32 lowerOverlap = (dstUpper - srcLower) / lineSize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (upperOverlap > 0 && lowerOverlap < 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				it->xfbAddr += lineSize * upperOverlap; | 
					
						
							|  |  |  | 				it->xfbHeight -= upperOverlap; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (lowerOverlap > 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				it->xfbHeight -= lowerOverlap; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | int FramebufferManagerBase::ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width) | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (g_ActiveConfig.RealXFBEnabled()) | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | 		return x; | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (g_ActiveConfig.b3DVision) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// This works, yet the version in the else doesn't. No idea why.
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | 		return x * (int)backbuffer_width / (int)FramebufferManagerBase::LastXfbWidth(); | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							| 
									
										
										
										
											2013-04-24 09:21:54 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | 		return x * (int)Renderer::GetTargetRectangle().GetWidth() / (int)FramebufferManagerBase::LastXfbWidth(); | 
					
						
							| 
									
										
										
										
											2013-04-24 09:21:54 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | int FramebufferManagerBase::ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height) | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (g_ActiveConfig.RealXFBEnabled()) | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | 		return y; | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (g_ActiveConfig.b3DVision) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// This works, yet the version in the else doesn't. No idea why.
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | 		return y * (int)backbuffer_height / (int)FramebufferManagerBase::LastXfbHeight(); | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							| 
									
										
										
										
											2013-04-24 09:21:54 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-10-02 22:11:15 +02:00
										 |  |  | 		return y * (int)Renderer::GetTargetRectangle().GetHeight() / (int)FramebufferManagerBase::LastXfbHeight(); | 
					
						
							| 
									
										
										
										
											2013-04-24 09:21:54 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-09-29 00:19:28 +02:00
										 |  |  | } |