Code cleanup. Juggling rectangles. I'm about to investigate the problems with Real XFB's in PAL games, so I wanted to make sure all our rectangles were cleaned up and organized.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3794 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
7a82ae0943
commit
f338d5c44c
|
@ -103,6 +103,38 @@ int ClassifyDouble(double dvalue);
|
||||||
// More efficient float version.
|
// More efficient float version.
|
||||||
int ClassifyFloat(float fvalue);
|
int ClassifyFloat(float fvalue);
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct Rectangle
|
||||||
|
{
|
||||||
|
T left;
|
||||||
|
T top;
|
||||||
|
T right;
|
||||||
|
T bottom;
|
||||||
|
|
||||||
|
T GetWidth() const { return abs(right - left); }
|
||||||
|
T GetHeight() const { return abs(bottom - top); }
|
||||||
|
|
||||||
|
// If the rectangle is in a coordinate system with a lower-left origin, use
|
||||||
|
// this Clamp.
|
||||||
|
void ClampLL(T x1, T y1, T x2, T y2)
|
||||||
|
{
|
||||||
|
if (left < x1) left = x1;
|
||||||
|
if (right > x2) right = x2;
|
||||||
|
if (top > y1) top = y1;
|
||||||
|
if (bottom < y2) bottom = y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the rectangle is in an coordinate system with an upper-left origin,
|
||||||
|
// use this Clamp.
|
||||||
|
void ClampUL(T x1, T y1, T x2, T y2)
|
||||||
|
{
|
||||||
|
if (left < x1) left = x1;
|
||||||
|
if (right > x2) right = x2;
|
||||||
|
if (top < y1) top = y1;
|
||||||
|
if (bottom > y2) bottom = y2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace MathUtil
|
} // namespace MathUtil
|
||||||
|
|
||||||
inline float pow2f(float x) {return x * x;}
|
inline float pow2f(float x) {return x * x;}
|
||||||
|
@ -158,5 +190,4 @@ public:
|
||||||
float data[16];
|
float data[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _MATH_UTIL_H_
|
#endif // _MATH_UTIL_H_
|
||||||
|
|
|
@ -45,11 +45,9 @@ void SetBlendMode(const Bypass &bp);
|
||||||
void SetDitherMode(const Bypass &bp);
|
void SetDitherMode(const Bypass &bp);
|
||||||
void SetLogicOpMode(const Bypass &bp);
|
void SetLogicOpMode(const Bypass &bp);
|
||||||
void SetColorMask(const Bypass &bp);
|
void SetColorMask(const Bypass &bp);
|
||||||
float GetRendererTargetScaleX();
|
void CopyEFB(const Bypass &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf);
|
||||||
float GetRendererTargetScaleY();
|
void RenderToXFB(const Bypass &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight);
|
||||||
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf);
|
void ClearScreen(const Bypass &bp, const EFBRectangle &rc);
|
||||||
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight);
|
|
||||||
void ClearScreen(const Bypass &bp, const TRectangle &multirc);
|
|
||||||
void RestoreRenderState(const Bypass &bp);
|
void RestoreRenderState(const Bypass &bp);
|
||||||
u8 *GetPointer(const u32 &address);
|
u8 *GetPointer(const u32 &address);
|
||||||
bool GetConfig(const int &type);
|
bool GetConfig(const int &type);
|
||||||
|
|
|
@ -176,24 +176,13 @@ void BPWritten(const Bypass& bp)
|
||||||
DVSTARTSUBPROFILE("LoadBPReg:swap");
|
DVSTARTSUBPROFILE("LoadBPReg:swap");
|
||||||
// The bottom right is within the rectangle
|
// The bottom right is within the rectangle
|
||||||
// The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function
|
// The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function
|
||||||
TRectangle rc = {
|
|
||||||
(int)(bpmem.copyTexSrcXY.x),
|
|
||||||
(int)(bpmem.copyTexSrcXY.y),
|
|
||||||
(int)((bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1)),
|
|
||||||
(int)((bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1))
|
|
||||||
};
|
|
||||||
|
|
||||||
float MValueX = GetRendererTargetScaleX();
|
EFBRectangle rc;
|
||||||
float MValueY = GetRendererTargetScaleY();
|
rc.left = (int)bpmem.copyTexSrcXY.x;
|
||||||
|
rc.top = (int)bpmem.copyTexSrcXY.y;
|
||||||
|
rc.right = (int)(bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1);
|
||||||
|
rc.bottom = (int)(bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1);
|
||||||
|
|
||||||
// Need another rc here to get it to scale.
|
|
||||||
// Here the bottom right is the out of the rectangle.
|
|
||||||
TRectangle multirc = {
|
|
||||||
(int)(bpmem.copyTexSrcXY.x * MValueX),
|
|
||||||
(int)(bpmem.copyTexSrcXY.y * MValueY),
|
|
||||||
(int)((bpmem.copyTexSrcXY.x * MValueX + (bpmem.copyTexSrcWH.x + 1) * MValueX)),
|
|
||||||
(int)((bpmem.copyTexSrcXY.y * MValueY + (bpmem.copyTexSrcWH.y + 1) * MValueY))
|
|
||||||
};
|
|
||||||
UPE_Copy PE_copy;
|
UPE_Copy PE_copy;
|
||||||
PE_copy.Hex = bpmem.triggerEFBCopy;
|
PE_copy.Hex = bpmem.triggerEFBCopy;
|
||||||
|
|
||||||
|
@ -219,7 +208,7 @@ void BPWritten(const Bypass& bp)
|
||||||
#endif
|
#endif
|
||||||
const float yScale = bpmem.dispcopyyscale / 256.0f;
|
const float yScale = bpmem.dispcopyyscale / 256.0f;
|
||||||
const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);
|
const float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);
|
||||||
RenderToXFB(bp, multirc, yScale, xfbLines,
|
RenderToXFB(bp, rc, yScale, xfbLines,
|
||||||
bpmem.copyTexDest << 5,
|
bpmem.copyTexDest << 5,
|
||||||
bpmem.copyMipMapStrideChannels << 4,
|
bpmem.copyMipMapStrideChannels << 4,
|
||||||
(u32)ceil(xfbLines));
|
(u32)ceil(xfbLines));
|
||||||
|
@ -227,7 +216,7 @@ void BPWritten(const Bypass& bp)
|
||||||
|
|
||||||
// Clear the picture after it's done and submitted, to prepare for the next picture
|
// Clear the picture after it's done and submitted, to prepare for the next picture
|
||||||
if (PE_copy.clear)
|
if (PE_copy.clear)
|
||||||
ClearScreen(bp, multirc);
|
ClearScreen(bp, rc);
|
||||||
|
|
||||||
RestoreRenderState(bp);
|
RestoreRenderState(bp);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ struct Statistics
|
||||||
float g2proj_0, g2proj_1, g2proj_2, g2proj_3, g2proj_4, g2proj_5;
|
float g2proj_0, g2proj_1, g2proj_2, g2proj_3, g2proj_4, g2proj_5;
|
||||||
float g2proj_6, g2proj_7, g2proj_8, g2proj_9, g2proj_10, g2proj_11, g2proj_12, g2proj_13, g2proj_14, g2proj_15;
|
float g2proj_6, g2proj_7, g2proj_8, g2proj_9, g2proj_10, g2proj_11, g2proj_12, g2proj_13, g2proj_14, g2proj_15;
|
||||||
|
|
||||||
std::vector<TRectangle> efb_regions;
|
std::vector<EFBRectangle> efb_regions;
|
||||||
|
|
||||||
struct ThisFrame
|
struct ThisFrame
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define _VIDEOCOMMON_H
|
#define _VIDEOCOMMON_H
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "MathUtil.h"
|
||||||
#include "pluginspecs_video.h"
|
#include "pluginspecs_video.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__x86_64__) && !defined(_M_X64)
|
#if defined(_MSC_VER) && !defined(__x86_64__) && !defined(_M_X64)
|
||||||
|
@ -40,9 +41,14 @@ enum
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
XFB_WIDTH = 640,
|
// XFB width is decided by EFB copy operation. The VI can do horizontal
|
||||||
XFB_HEIGHT = 480, // 574 can be used with tricks (multi pass render and dual xfb copies, etc).
|
// scaling (TODO: emulate).
|
||||||
// TODO: figure out what to do with PAL
|
MAX_XFB_WIDTH = EFB_WIDTH,
|
||||||
|
|
||||||
|
// Although EFB height is 528, 574-line XFB's can be created either with
|
||||||
|
// vertical scaling by the EFB copy operation or copying to multiple XFB's
|
||||||
|
// that are next to each other in memory (TODO: handle that situation).
|
||||||
|
MAX_XFB_HEIGHT = 574
|
||||||
};
|
};
|
||||||
|
|
||||||
// If this is enabled, bounding boxes will be computed for everything drawn.
|
// If this is enabled, bounding boxes will be computed for everything drawn.
|
||||||
|
@ -54,11 +60,6 @@ enum
|
||||||
|
|
||||||
extern SVideoInitialize g_VideoInitialize;
|
extern SVideoInitialize g_VideoInitialize;
|
||||||
|
|
||||||
// (mb2) for XFB update hack. TODO: find a static better place
|
|
||||||
extern volatile u32 g_XFBUpdateRequested;
|
|
||||||
|
|
||||||
extern volatile bool g_EFBAccessRequested;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
inline u8 *Memory_GetPtr(u32 _uAddress)
|
inline u8 *Memory_GetPtr(u32 _uAddress)
|
||||||
{
|
{
|
||||||
|
@ -103,48 +104,11 @@ inline float Memory_Read_Float(u32 _uAddress)
|
||||||
return temp.f;
|
return temp.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TRectangle
|
// This structure should only be used to represent a rectangle in EFB
|
||||||
{
|
// coordinates, where the origin is at the upper left and the frame dimensions
|
||||||
int left;
|
// are 640 x 528.
|
||||||
int top;
|
struct EFBRectangle : public MathUtil::Rectangle<int>
|
||||||
int right;
|
{};
|
||||||
int bottom;
|
|
||||||
|
|
||||||
int GetWidth() const { return right - left; }
|
|
||||||
int GetHeight() const { return bottom - top; }
|
|
||||||
|
|
||||||
void FlipYPosition(int y_height, TRectangle *dest) const
|
|
||||||
{
|
|
||||||
int offset = y_height - (bottom - top);
|
|
||||||
dest->left = left;
|
|
||||||
dest->top = top + offset;
|
|
||||||
dest->right = right;
|
|
||||||
dest->bottom = bottom + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlipY(int y_height, TRectangle *dest) const {
|
|
||||||
dest->left = left;
|
|
||||||
dest->right = right;
|
|
||||||
dest->bottom = y_height - bottom;
|
|
||||||
dest->top = y_height - top;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scale(float factor_x, float factor_y, TRectangle *dest) const
|
|
||||||
{
|
|
||||||
dest->left = (int)(factor_x * left);
|
|
||||||
dest->right = (int)(factor_x * right);
|
|
||||||
dest->top = (int)(factor_y * top);
|
|
||||||
dest->bottom = (int)(factor_y * bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clamp(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
if (left < x1) left = x1;
|
|
||||||
if (right > x2) right = x2;
|
|
||||||
if (top < y1) top = y1;
|
|
||||||
if (bottom > y2) bottom = y2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
// ¯¯¯¯¯¯¯¯¯¯
|
// ¯¯¯¯¯¯¯¯¯¯
|
||||||
|
|
|
@ -214,28 +214,25 @@ void SetColorMask(const Bypass &bp)
|
||||||
|
|
||||||
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write);
|
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write);
|
||||||
}
|
}
|
||||||
float GetRendererTargetScaleX()
|
|
||||||
{
|
void CopyEFB(const Bypass &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf)
|
||||||
return Renderer::GetXScale();
|
|
||||||
}
|
|
||||||
float GetRendererTargetScaleY()
|
|
||||||
{
|
|
||||||
return Renderer::GetYScale();
|
|
||||||
}
|
|
||||||
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf)
|
|
||||||
{
|
{
|
||||||
|
// TODO: Scale EFBRectangle correctly
|
||||||
|
|
||||||
RECT rec = { rc.left, rc.top, rc.right, rc.bottom };
|
RECT rec = { rc.left, rc.top, rc.right, rc.bottom };
|
||||||
TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec);
|
TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
|
void RenderToXFB(const Bypass &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
|
||||||
{
|
{
|
||||||
Renderer::SwapBuffers();
|
Renderer::SwapBuffers();
|
||||||
PRIM_LOG("Renderer::SwapBuffers()");
|
PRIM_LOG("Renderer::SwapBuffers()");
|
||||||
g_VideoInitialize.pCopiedToXFB();
|
g_VideoInitialize.pCopiedToXFB();
|
||||||
}
|
}
|
||||||
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
|
void ClearScreen(const Bypass &bp, const EFBRectangle &rc)
|
||||||
{
|
{
|
||||||
|
// TODO: Scale EFBRectangle correctly
|
||||||
|
|
||||||
// it seems that the GC is able to alpha blend on color-fill
|
// it seems that the GC is able to alpha blend on color-fill
|
||||||
// we cant do that so if alpha is != 255 we skip it
|
// we cant do that so if alpha is != 255 we skip it
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,6 @@ u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y)
|
||||||
|
|
||||||
if (g_VideoInitialize.bUseDualCore)
|
if (g_VideoInitialize.bUseDualCore)
|
||||||
{
|
{
|
||||||
g_EFBAccessRequested = true;
|
|
||||||
s_AccessEFBDone.Init();
|
s_AccessEFBDone.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,19 +110,13 @@ void SetLogicOpMode(const Bypass &bp)
|
||||||
else
|
else
|
||||||
glDisable(GL_COLOR_LOGIC_OP);
|
glDisable(GL_COLOR_LOGIC_OP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetColorMask(const Bypass &bp)
|
void SetColorMask(const Bypass &bp)
|
||||||
{
|
{
|
||||||
Renderer::SetColorMask();
|
Renderer::SetColorMask();
|
||||||
}
|
}
|
||||||
float GetRendererTargetScaleX()
|
|
||||||
{
|
void CopyEFB(const Bypass &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf)
|
||||||
return Renderer::GetTargetScaleX();
|
|
||||||
}
|
|
||||||
float GetRendererTargetScaleY()
|
|
||||||
{
|
|
||||||
return Renderer::GetTargetScaleY();
|
|
||||||
}
|
|
||||||
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const bool &scaleByHalf)
|
|
||||||
{
|
{
|
||||||
// bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format)
|
// bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format)
|
||||||
if (!g_Config.bEFBCopyDisable)
|
if (!g_Config.bEFBCopyDisable)
|
||||||
|
@ -132,49 +126,24 @@ void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const b
|
||||||
TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
|
TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
|
void RenderToXFB(const Bypass &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
|
||||||
{
|
{
|
||||||
Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, multirc);
|
Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, rc);
|
||||||
}
|
}
|
||||||
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
|
|
||||||
|
void ClearScreen(const Bypass &bp, const EFBRectangle &rc)
|
||||||
{
|
{
|
||||||
// Update the view port for clearing the picture
|
bool colorEnable = bpmem.blendmode.colorupdate;
|
||||||
glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight());
|
bool alphaEnable = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24 && bpmem.blendmode.alphaupdate);
|
||||||
|
bool zEnable = bpmem.zmode.updateenable;
|
||||||
|
|
||||||
// Always set the scissor in case it was set by the game and has not been reset
|
if (colorEnable || alphaEnable || zEnable)
|
||||||
glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom),
|
|
||||||
(multirc.right - multirc.left), (multirc.bottom - multirc.top));
|
|
||||||
// ---------------------------
|
|
||||||
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
|
|
||||||
// Since clear operations use the source rectangle, we have to do
|
|
||||||
// regular renders (glClear clears the entire buffer)
|
|
||||||
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate || bpmem.zmode.updateenable)
|
|
||||||
{
|
{
|
||||||
GLbitfield bits = 0;
|
u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
|
||||||
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
|
u32 z = bpmem.clearZValue;
|
||||||
{
|
|
||||||
u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
|
|
||||||
|
|
||||||
// Alpha may or may not be present depending on the EFB pixel format.
|
Renderer::ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z);
|
||||||
GLclampf clearAlpha = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) ?
|
}
|
||||||
((clearColor>>24) & 0xff)*(1/255.0f) : 1.0f;
|
|
||||||
|
|
||||||
glClearColor(((clearColor>>16) & 0xff)*(1/255.0f),
|
|
||||||
((clearColor>>8 ) & 0xff)*(1/255.0f),
|
|
||||||
((clearColor>>0 ) & 0xff)*(1/255.0f),
|
|
||||||
clearAlpha);
|
|
||||||
bits |= GL_COLOR_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
if (bpmem.zmode.updateenable)
|
|
||||||
{
|
|
||||||
glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF));
|
|
||||||
bits |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
|
||||||
glClear(bits);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestoreRenderState(const Bypass &bp)
|
void RestoreRenderState(const Bypass &bp)
|
||||||
|
|
|
@ -183,7 +183,7 @@ void FramebufferManager::Shutdown()
|
||||||
m_virtualXFBList.clear();
|
m_virtualXFBList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
||||||
{
|
{
|
||||||
if (g_Config.bUseXFB)
|
if (g_Config.bUseXFB)
|
||||||
copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
||||||
|
@ -199,7 +199,7 @@ const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32
|
||||||
return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight);
|
return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
|
GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) const
|
||||||
{
|
{
|
||||||
if (m_msaaSamples <= 1)
|
if (m_msaaSamples <= 1)
|
||||||
{
|
{
|
||||||
|
@ -210,17 +210,15 @@ GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
|
||||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
||||||
// required.
|
// required.
|
||||||
|
|
||||||
// Flip source rectangle upside-down for OpenGL.
|
TargetRectangle targetRc = ConvertEFBRectangle(sourceRc);
|
||||||
TRectangle glRect;
|
targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight);
|
||||||
sourceRc.FlipYPosition(m_targetHeight, &glRect);
|
|
||||||
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
|
|
||||||
|
|
||||||
// Resolve.
|
// Resolve.
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
||||||
glBlitFramebufferEXT(
|
glBlitFramebufferEXT(
|
||||||
glRect.left, glRect.top, glRect.right, glRect.bottom,
|
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||||
glRect.left, glRect.top, glRect.right, glRect.bottom,
|
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -231,7 +229,7 @@ GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
|
GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc) const
|
||||||
{
|
{
|
||||||
if (m_msaaSamples <= 1)
|
if (m_msaaSamples <= 1)
|
||||||
{
|
{
|
||||||
|
@ -242,17 +240,15 @@ GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
|
||||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
||||||
// required.
|
// required.
|
||||||
|
|
||||||
// Flip source rectangle upside-down for OpenGL.
|
TargetRectangle targetRc = ConvertEFBRectangle(sourceRc);
|
||||||
TRectangle glRect;
|
targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight);
|
||||||
sourceRc.FlipYPosition(m_targetHeight, &glRect);
|
|
||||||
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
|
|
||||||
|
|
||||||
// Resolve.
|
// Resolve.
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
||||||
glBlitFramebufferEXT(
|
glBlitFramebufferEXT(
|
||||||
glRect.left, glRect.top, glRect.right, glRect.bottom,
|
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||||
glRect.left, glRect.top, glRect.right, glRect.bottom,
|
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||||
GL_DEPTH_BUFFER_BIT, GL_NEAREST
|
GL_DEPTH_BUFFER_BIT, GL_NEAREST
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -263,6 +259,16 @@ GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TargetRectangle FramebufferManager::ConvertEFBRectangle(const EFBRectangle& rc) const
|
||||||
|
{
|
||||||
|
TargetRectangle result;
|
||||||
|
result.left = rc.left * m_targetWidth / EFB_WIDTH;
|
||||||
|
result.top = m_targetHeight - (rc.top * m_targetHeight / EFB_HEIGHT);
|
||||||
|
result.right = rc.right * m_targetWidth / EFB_WIDTH;
|
||||||
|
result.bottom = m_targetHeight - (rc.bottom * m_targetHeight / EFB_HEIGHT);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FramebufferManager::VirtualXFBListType::iterator
|
FramebufferManager::VirtualXFBListType::iterator
|
||||||
FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
||||||
{
|
{
|
||||||
|
@ -283,7 +289,7 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
||||||
return m_virtualXFBList.end();
|
return m_virtualXFBList.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
||||||
{
|
{
|
||||||
u8* pXFB = Memory_GetPtr(xfbAddr);
|
u8* pXFB = Memory_GetPtr(xfbAddr);
|
||||||
if (!pXFB)
|
if (!pXFB)
|
||||||
|
@ -295,7 +301,7 @@ void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, c
|
||||||
XFB_Write(pXFB, sourceRc, fbWidth, fbHeight);
|
XFB_Write(pXFB, sourceRc, fbWidth, fbHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
||||||
{
|
{
|
||||||
GLuint xfbTexture;
|
GLuint xfbTexture;
|
||||||
|
|
||||||
|
@ -311,7 +317,7 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight
|
||||||
|
|
||||||
it->xfbSource.texWidth = m_targetWidth;
|
it->xfbSource.texWidth = m_targetWidth;
|
||||||
it->xfbSource.texHeight = m_targetHeight;
|
it->xfbSource.texHeight = m_targetHeight;
|
||||||
it->xfbSource.sourceRc = sourceRc;
|
it->xfbSource.sourceRc = ConvertEFBRectangle(sourceRc);
|
||||||
|
|
||||||
xfbTexture = it->xfbSource.texture;
|
xfbTexture = it->xfbSource.texture;
|
||||||
|
|
||||||
|
@ -348,7 +354,7 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight
|
||||||
newVirt.xfbSource.texture = xfbTexture;
|
newVirt.xfbSource.texture = xfbTexture;
|
||||||
newVirt.xfbSource.texWidth = m_targetWidth;
|
newVirt.xfbSource.texWidth = m_targetWidth;
|
||||||
newVirt.xfbSource.texHeight = m_targetHeight;
|
newVirt.xfbSource.texHeight = m_targetHeight;
|
||||||
newVirt.xfbSource.sourceRc = sourceRc;
|
newVirt.xfbSource.sourceRc = ConvertEFBRectangle(sourceRc);
|
||||||
|
|
||||||
// Add the new Virtual XFB to the list
|
// Add the new Virtual XFB to the list
|
||||||
|
|
||||||
|
@ -407,20 +413,22 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight
|
||||||
|
|
||||||
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||||
{
|
{
|
||||||
m_realXFBSource.texWidth = XFB_WIDTH;
|
m_realXFBSource.texWidth = MAX_XFB_WIDTH;
|
||||||
m_realXFBSource.texHeight = XFB_HEIGHT;
|
m_realXFBSource.texHeight = MAX_XFB_HEIGHT;
|
||||||
|
|
||||||
|
// 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.left = 0;
|
||||||
m_realXFBSource.sourceRc.top = 0;
|
m_realXFBSource.sourceRc.top = fbHeight;
|
||||||
m_realXFBSource.sourceRc.right = fbWidth;
|
m_realXFBSource.sourceRc.right = fbWidth;
|
||||||
m_realXFBSource.sourceRc.bottom = fbHeight;
|
m_realXFBSource.sourceRc.bottom = 0;
|
||||||
|
|
||||||
if (!m_realXFBSource.texture)
|
if (!m_realXFBSource.texture)
|
||||||
{
|
{
|
||||||
glGenTextures(1, &m_realXFBSource.texture);
|
glGenTextures(1, &m_realXFBSource.texture);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture);
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture);
|
||||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ struct XFBSource
|
||||||
int texWidth;
|
int texWidth;
|
||||||
int texHeight;
|
int texHeight;
|
||||||
|
|
||||||
TRectangle sourceRc;
|
TargetRectangle sourceRc;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FramebufferManager
|
class FramebufferManager
|
||||||
|
@ -95,19 +95,19 @@ public:
|
||||||
void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
|
void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
// sourceRc is in GL target coordinates, not GameCube EFB coordinates!
|
void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
||||||
// TODO: Clean that up.
|
|
||||||
void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
|
||||||
|
|
||||||
const XFBSource* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
const XFBSource* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||||
|
|
||||||
// To get the EFB in texture form, these functions may have to transfer
|
// To get the EFB in texture form, these functions may have to transfer
|
||||||
// the EFB to a resolved texture first.
|
// the EFB to a resolved texture first.
|
||||||
GLuint GetEFBColorTexture(const TRectangle& sourceRc) const;
|
GLuint GetEFBColorTexture(const EFBRectangle& sourceRc) const;
|
||||||
GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const;
|
GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc) const;
|
||||||
|
|
||||||
GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; }
|
GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; }
|
||||||
|
|
||||||
|
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct VirtualXFB
|
struct VirtualXFB
|
||||||
|
@ -124,8 +124,8 @@ private:
|
||||||
|
|
||||||
VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
|
VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
|
||||||
|
|
||||||
void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
||||||
void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
||||||
const XFBSource* getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
const XFBSource* getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||||
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "nGLUtil.h"
|
#include "nGLUtil.h"
|
||||||
#else
|
#else
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "MathUtil.h"
|
||||||
#include "pluginspecs_video.h"
|
#include "pluginspecs_video.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -112,6 +113,13 @@ extern GLWindow GLWin;
|
||||||
|
|
||||||
// Public OpenGL util
|
// Public OpenGL util
|
||||||
|
|
||||||
|
// This structure should only be used to represent a rectangle in OpenGL target
|
||||||
|
// coordinates, where the origin is at the lower left and the frame dimensions
|
||||||
|
// depend on the resolution settings. Use Renderer::ConvertEFBRectangle to
|
||||||
|
// convert an EFBRectangle to a TargetRectangle.
|
||||||
|
struct TargetRectangle : public MathUtil::Rectangle<int>
|
||||||
|
{};
|
||||||
|
|
||||||
// Initialization / upkeep
|
// Initialization / upkeep
|
||||||
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height);
|
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height);
|
||||||
void OpenGL_Shutdown();
|
void OpenGL_Shutdown();
|
||||||
|
|
|
@ -442,6 +442,11 @@ float Renderer::GetTargetScaleY()
|
||||||
return (float)GetTargetHeight() / (float)EFB_HEIGHT;
|
return (float)GetTargetHeight() / (float)EFB_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||||
|
{
|
||||||
|
return s_framebufferManager.ConvertEFBRectangle(rc);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::SetFramebuffer(GLuint fb)
|
void Renderer::SetFramebuffer(GLuint fb)
|
||||||
{
|
{
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_framebufferManager.GetEFBFramebuffer());
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_framebufferManager.GetEFBFramebuffer());
|
||||||
|
@ -451,15 +456,15 @@ void Renderer::ResetGLState()
|
||||||
{
|
{
|
||||||
// Gets us to a reasonably sane state where it's possible to do things like
|
// Gets us to a reasonably sane state where it's possible to do things like
|
||||||
// image copies with textured quads, etc.
|
// image copies with textured quads, etc.
|
||||||
|
glDisable(GL_VERTEX_PROGRAM_ARB);
|
||||||
|
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||||
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
|
||||||
glDisable(GL_VERTEX_PROGRAM_ARB);
|
|
||||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateViewport();
|
void UpdateViewport();
|
||||||
|
@ -533,13 +538,76 @@ void Renderer::SetBlendMode(bool forceUpdate)
|
||||||
s_blendMode = newval;
|
s_blendMode = newval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||||
|
{
|
||||||
|
// Get the rectangular target region covered by the EFB pixel.
|
||||||
|
EFBRectangle efbPixelRc;
|
||||||
|
efbPixelRc.left = x;
|
||||||
|
efbPixelRc.top = y;
|
||||||
|
efbPixelRc.right = x + 1;
|
||||||
|
efbPixelRc.bottom = y + 1;
|
||||||
|
|
||||||
|
TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
|
||||||
|
case PEEK_Z:
|
||||||
|
{
|
||||||
|
if (s_MSAASamples > 1)
|
||||||
|
{
|
||||||
|
// XXX: What is this? Binding a texture to a framebuffer slot?
|
||||||
|
// It's not documented in the OpenGL spec, but it seems to work!
|
||||||
|
// (ATI Radeon HD 3870, CATALYST 9.6 drivers, Windows Vista 64-bit...)
|
||||||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ResolveAndGetDepthTarget(efbPixelRc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sample from the center of the target region.
|
||||||
|
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||||
|
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||||
|
|
||||||
|
u32 z;
|
||||||
|
glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z);
|
||||||
|
GL_REPORT_ERRORD();
|
||||||
|
|
||||||
|
if (s_MSAASamples > 1)
|
||||||
|
{
|
||||||
|
// Return to the EFB (this may not be necessary).
|
||||||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the 32-bit value returned by glReadPixels to a 24-bit
|
||||||
|
// value (GC uses a 24-bit Z-buffer).
|
||||||
|
return z >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
case POKE_Z:
|
||||||
|
// TODO: Implement
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PEEK_COLOR:
|
||||||
|
// TODO: Implement
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POKE_COLOR:
|
||||||
|
// TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
|
||||||
|
// the exact location. Note: EFB pokes are susceptible to Z-buffering
|
||||||
|
// and perhaps blending.
|
||||||
|
//WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply AA if enabled
|
// Apply AA if enabled
|
||||||
GLuint Renderer::ResolveAndGetRenderTarget(const TRectangle &source_rect)
|
GLuint Renderer::ResolveAndGetRenderTarget(const EFBRectangle &source_rect)
|
||||||
{
|
{
|
||||||
return s_framebufferManager.GetEFBColorTexture(source_rect);
|
return s_framebufferManager.GetEFBColorTexture(source_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint Renderer::ResolveAndGetDepthTarget(const TRectangle &source_rect)
|
GLuint Renderer::ResolveAndGetDepthTarget(const EFBRectangle &source_rect)
|
||||||
{
|
{
|
||||||
return s_framebufferManager.GetEFBDepthTexture(source_rect);
|
return s_framebufferManager.GetEFBDepthTexture(source_rect);
|
||||||
}
|
}
|
||||||
|
@ -600,7 +668,7 @@ bool Renderer::SetScissorRect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aspect ratio functions
|
// Aspect ratio functions
|
||||||
void ComputeBackbufferRectangle(TRectangle *rc)
|
static void ComputeBackbufferRectangle(TargetRectangle *rc)
|
||||||
{
|
{
|
||||||
float FloatGLWidth = (float)OpenGL_GetBackbufferWidth();
|
float FloatGLWidth = (float)OpenGL_GetBackbufferWidth();
|
||||||
float FloatGLHeight = (float)OpenGL_GetBackbufferHeight();
|
float FloatGLHeight = (float)OpenGL_GetBackbufferHeight();
|
||||||
|
@ -657,12 +725,45 @@ void ComputeBackbufferRectangle(TRectangle *rc)
|
||||||
int XOffset = floor(FloatXOffset + 0.5);
|
int XOffset = floor(FloatXOffset + 0.5);
|
||||||
int YOffset = floor(FloatYOffset + 0.5);
|
int YOffset = floor(FloatYOffset + 0.5);
|
||||||
rc->left = XOffset;
|
rc->left = XOffset;
|
||||||
rc->top = YOffset;
|
rc->top = YOffset + ceil(FloatGLHeight);
|
||||||
rc->right = XOffset + ceil(FloatGLWidth);
|
rc->right = XOffset + ceil(FloatGLWidth);
|
||||||
rc->bottom = YOffset + ceil(FloatGLHeight);
|
rc->bottom = YOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
|
||||||
|
{
|
||||||
|
// Update the view port for clearing the picture
|
||||||
|
glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight());
|
||||||
|
|
||||||
|
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
|
||||||
|
|
||||||
|
// Always set the scissor in case it was set by the game and has not been reset
|
||||||
|
glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
||||||
|
|
||||||
|
VertexShaderManager::SetViewportChanged();
|
||||||
|
|
||||||
|
GLbitfield bits = 0;
|
||||||
|
if (colorEnable)
|
||||||
|
{
|
||||||
|
bits |= GL_COLOR_BUFFER_BIT;
|
||||||
|
glClearColor(
|
||||||
|
((color >> 16) & 0xFF) / 255.0f,
|
||||||
|
((color >> 8) & 0xFF) / 255.0f,
|
||||||
|
(color & 0xFF) / 255.0f,
|
||||||
|
(alphaEnable ? ((color >> 24) & 0xFF) / 255.0f : 1.0f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (zEnable)
|
||||||
|
{
|
||||||
|
bits |= GL_DEPTH_BUFFER_BIT;
|
||||||
|
glClearDepth((z & 0xFFFFFF) / float(0xFFFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||||
|
glClear(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
||||||
{
|
{
|
||||||
// If we're about to write to a requested XFB, make sure the previous
|
// If we're about to write to a requested XFB, make sure the previous
|
||||||
// contents make it to the screen first.
|
// contents make it to the screen first.
|
||||||
|
@ -686,29 +787,26 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||||
|
|
||||||
ResetGLState();
|
ResetGLState();
|
||||||
|
|
||||||
TRectangle back_rc;
|
TargetRectangle back_rc;
|
||||||
ComputeBackbufferRectangle(&back_rc);
|
ComputeBackbufferRectangle(&back_rc);
|
||||||
|
|
||||||
float u_max;
|
TargetRectangle sourceRc;
|
||||||
float v_min;
|
|
||||||
float v_max;
|
|
||||||
|
|
||||||
if (g_Config.bAutoScale)
|
if (g_Config.bAutoScale || g_Config.bUseXFB)
|
||||||
{
|
{
|
||||||
u_max = (xfbSource->sourceRc.right - xfbSource->sourceRc.left);
|
sourceRc = xfbSource->sourceRc;
|
||||||
v_min = (float)xfbSource->texHeight - (xfbSource->sourceRc.bottom - xfbSource->sourceRc.top);
|
|
||||||
v_max = (float)xfbSource->texHeight;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u_max = (float)xfbSource->texWidth;
|
sourceRc.left = 0;
|
||||||
v_min = 0.f;
|
sourceRc.top = xfbSource->texHeight;
|
||||||
v_max = (float)xfbSource->texHeight;
|
sourceRc.right = xfbSource->texWidth;
|
||||||
|
sourceRc.bottom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yOffset = (g_Config.bUseXFB && field == FIELD_LOWER) ? -1 : 0;
|
int yOffset = (g_Config.bUseXFB && field == FIELD_LOWER) ? -1 : 0;
|
||||||
v_min -= yOffset;
|
sourceRc.top -= yOffset;
|
||||||
v_max -= yOffset;
|
sourceRc.bottom -= yOffset;
|
||||||
|
|
||||||
// Tell the OSD Menu about the current internal resolution
|
// Tell the OSD Menu about the current internal resolution
|
||||||
OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight();
|
OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight();
|
||||||
|
@ -723,8 +821,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||||
TextureMngr::DisableStage(i);
|
TextureMngr::DisableStage(i);
|
||||||
|
|
||||||
// Update GLViewPort
|
// Update GLViewPort
|
||||||
glViewport(back_rc.left, back_rc.top,
|
glViewport(back_rc.left, back_rc.bottom, back_rc.GetWidth(), back_rc.GetHeight());
|
||||||
back_rc.right - back_rc.left, back_rc.bottom - back_rc.top);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
|
|
||||||
|
@ -746,10 +843,10 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||||
if (PostProcessing::ApplyShader())
|
if (PostProcessing::ApplyShader())
|
||||||
{
|
{
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glTexCoord2f(0, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(-1, -1);
|
glTexCoord2f(sourceRc.left, sourceRc.bottom); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); glVertex2f(-1, -1);
|
||||||
glTexCoord2f(0, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(-1, 1);
|
glTexCoord2f(sourceRc.left, sourceRc.top); glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); glVertex2f(-1, 1);
|
||||||
glTexCoord2f(u_max, v_max); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f( 1, 1);
|
glTexCoord2f(sourceRc.right, sourceRc.top); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); glVertex2f( 1, 1);
|
||||||
glTexCoord2f(u_max, v_min); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f( 1, -1);
|
glTexCoord2f(sourceRc.right, sourceRc.bottom); glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); glVertex2f( 1, -1);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
|
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
|
||||||
|
@ -758,10 +855,10 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glTexCoord2f(0, v_min); glVertex2f(-1, -1);
|
glTexCoord2f(sourceRc.left, sourceRc.bottom); glVertex2f(-1, -1);
|
||||||
glTexCoord2f(0, v_max); glVertex2f(-1, 1);
|
glTexCoord2f(sourceRc.left, sourceRc.top); glVertex2f(-1, 1);
|
||||||
glTexCoord2f(u_max, v_max); glVertex2f( 1, 1);
|
glTexCoord2f(sourceRc.right, sourceRc.top); glVertex2f( 1, 1);
|
||||||
glTexCoord2f(u_max, v_min); glVertex2f( 1, -1);
|
glTexCoord2f(sourceRc.right, sourceRc.bottom); glVertex2f( 1, -1);
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,7 +880,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||||
|
|
||||||
s_criticalScreenshot.Enter();
|
s_criticalScreenshot.Enter();
|
||||||
// Save screenshot
|
// Save screenshot
|
||||||
SaveRenderTarget(s_sScreenshotName.c_str(), xfbSource->sourceRc.GetWidth(), xfbSource->sourceRc.GetHeight(), (int)(v_min));
|
SaveRenderTarget(s_sScreenshotName.c_str(), xfbSource->sourceRc.GetWidth(), xfbSource->sourceRc.GetHeight(), yOffset);
|
||||||
// Reset settings
|
// Reset settings
|
||||||
s_sScreenshotName = "";
|
s_sScreenshotName = "";
|
||||||
s_bScreenshot = false;
|
s_bScreenshot = false;
|
||||||
|
@ -806,7 +903,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||||
s_criticalScreenshot.Enter();
|
s_criticalScreenshot.Enter();
|
||||||
int w = xfbSource->sourceRc.GetWidth();
|
int w = xfbSource->sourceRc.GetWidth();
|
||||||
int h = xfbSource->sourceRc.GetHeight();
|
int h = xfbSource->sourceRc.GetHeight();
|
||||||
int t = (int)(v_min);
|
int t = yOffset;
|
||||||
u8 *data = (u8 *) malloc(3 * w * h);
|
u8 *data = (u8 *) malloc(3 * w * h);
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
glReadPixels(0, t, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
|
glReadPixels(0, t, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
|
||||||
|
@ -1005,8 +1102,10 @@ void Renderer::DrawDebugText()
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
|
|
||||||
// Draw EFB copy regions rectangles
|
// Draw EFB copy regions rectangles
|
||||||
for (std::vector<TRectangle>::const_iterator it = stats.efb_regions.begin(); it != stats.efb_regions.end(); ++it)
|
for (std::vector<EFBRectangle>::const_iterator it = stats.efb_regions.begin(); it != stats.efb_regions.end(); ++it)
|
||||||
{
|
{
|
||||||
|
// TODO: Scale EFBRectangles correctly
|
||||||
|
|
||||||
GLfloat halfWidth = Renderer::GetTargetWidth() / 2.0f;
|
GLfloat halfWidth = Renderer::GetTargetWidth() / 2.0f;
|
||||||
GLfloat halfHeight = Renderer::GetTargetHeight() / 2.0f;
|
GLfloat halfHeight = Renderer::GetTargetHeight() / 2.0f;
|
||||||
GLfloat x = (GLfloat) -1.0f + ((GLfloat)it->left / halfWidth);
|
GLfloat x = (GLfloat) -1.0f + ((GLfloat)it->left / halfWidth);
|
||||||
|
@ -1257,13 +1356,9 @@ void Renderer::FlipImageData(u8 *data, int w, int h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
// This function does not have the final picture. Use Renderer::Swap() to adjust the final picture.
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: This function does not have the final picture. Use Renderer::Swap() to adjust the final picture.
|
|
||||||
// Call schedule: Called from VertexShaderManager
|
// Call schedule: Called from VertexShaderManager
|
||||||
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
|
|
||||||
void UpdateViewport()
|
void UpdateViewport()
|
||||||
{
|
{
|
||||||
// ---------
|
// ---------
|
||||||
|
|
|
@ -68,17 +68,21 @@ public:
|
||||||
static float GetTargetScaleX();
|
static float GetTargetScaleX();
|
||||||
static float GetTargetScaleY();
|
static float GetTargetScaleY();
|
||||||
|
|
||||||
|
static TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc);
|
||||||
|
|
||||||
static void SetFramebuffer(GLuint fb);
|
static void SetFramebuffer(GLuint fb);
|
||||||
|
|
||||||
|
static u32 AccessEFB(EFBAccessType type, int x, int y);
|
||||||
|
|
||||||
// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID.
|
// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID.
|
||||||
// Thus, this call may be expensive. Don't repeat it unnecessarily.
|
// Thus, this call may be expensive. Don't repeat it unnecessarily.
|
||||||
// If not in MSAA mode, will just return the render target texture ID.
|
// If not in MSAA mode, will just return the render target texture ID.
|
||||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
||||||
static GLuint ResolveAndGetRenderTarget(const TRectangle &rect);
|
static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect);
|
||||||
|
|
||||||
// Same as above but for the depth Target.
|
// Same as above but for the depth Target.
|
||||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
||||||
static GLuint ResolveAndGetDepthTarget(const TRectangle &rect);
|
static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect);
|
||||||
|
|
||||||
// Random utilities
|
// Random utilities
|
||||||
static void RenderText(const char* pstr, int left, int top, u32 color);
|
static void RenderText(const char* pstr, int left, int top, u32 color);
|
||||||
|
@ -87,12 +91,11 @@ public:
|
||||||
static void FlipImageData(u8 *data, int w, int h);
|
static void FlipImageData(u8 *data, int w, int h);
|
||||||
static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0);
|
static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0);
|
||||||
|
|
||||||
static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
static void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||||
|
static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
||||||
|
|
||||||
// Finish up the current frame, print some stats
|
// Finish up the current frame, print some stats
|
||||||
static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight);
|
static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight);
|
||||||
};
|
};
|
||||||
|
|
||||||
void ComputeBackbufferRectangle(TRectangle *rc);
|
|
||||||
|
|
||||||
#endif // _GCOGL_RENDER_H_
|
#endif // _GCOGL_RENDER_H_
|
||||||
|
|
|
@ -166,7 +166,7 @@ void Shutdown()
|
||||||
s_texConvFrameBuffer = 0;
|
s_texConvFrameBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TRectangle& sourceRc,
|
void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||||
u8* destAddr, int dstWidth, int dstHeight, bool linearFilter)
|
u8* destAddr, int dstWidth, int dstHeight, bool linearFilter)
|
||||||
{
|
{
|
||||||
Renderer::ResetGLState();
|
Renderer::ResetGLState();
|
||||||
|
@ -228,7 +228,7 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TRe
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle& source)
|
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle& source)
|
||||||
{
|
{
|
||||||
u32 format = copyfmt;
|
u32 format = copyfmt;
|
||||||
|
|
||||||
|
@ -250,10 +250,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf
|
||||||
|
|
||||||
u8 *dest_ptr = Memory_GetPtr(address);
|
u8 *dest_ptr = Memory_GetPtr(address);
|
||||||
|
|
||||||
TRectangle scaledTargetSource;
|
GLuint source_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(source) : Renderer::ResolveAndGetRenderTarget(source);
|
||||||
source.Scale(Renderer::GetTargetScaleX(), Renderer::GetTargetScaleY(), &scaledTargetSource);
|
|
||||||
|
|
||||||
u32 source_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(scaledTargetSource) : Renderer::ResolveAndGetRenderTarget(scaledTargetSource);
|
|
||||||
int width = source.right - source.left;
|
int width = source.right - source.left;
|
||||||
int height = source.bottom - source.top;
|
int height = source.bottom - source.top;
|
||||||
|
|
||||||
|
@ -291,7 +288,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf
|
||||||
|
|
||||||
TextureConversionShader::SetShaderParameters((float)expandedWidth, expandedHeight * MValueY, source.left * MValueX, top, sampleStride * MValueX, sampleStride * MValueY);
|
TextureConversionShader::SetShaderParameters((float)expandedWidth, expandedHeight * MValueY, source.left * MValueX, top, sampleStride * MValueX, sampleStride * MValueY);
|
||||||
|
|
||||||
TRectangle scaledSource;
|
TargetRectangle scaledSource;
|
||||||
scaledSource.top = 0;
|
scaledSource.top = 0;
|
||||||
scaledSource.bottom = expandedHeight;
|
scaledSource.bottom = expandedHeight;
|
||||||
scaledSource.left = 0;
|
scaledSource.left = 0;
|
||||||
|
@ -300,7 +297,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf
|
||||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, bScaleByHalf);
|
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, bScaleByHalf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeToRamYUYV(GLuint srcTexture, const TRectangle& sourceRc,
|
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||||
u8* destAddr, int dstWidth, int dstHeight)
|
u8* destAddr, int dstWidth, int dstHeight)
|
||||||
{
|
{
|
||||||
EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, false);
|
EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, false);
|
||||||
|
|
|
@ -30,9 +30,9 @@ void Init();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
||||||
u32 copyfmt, bool bScaleByHalf, const TRectangle& source);
|
u32 copyfmt, bool bScaleByHalf, const EFBRectangle& source);
|
||||||
|
|
||||||
void EncodeToRamYUYV(GLuint srcTexture, const TRectangle& sourceRc,
|
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||||
u8* destAddr, int dstWidth, int dstHeight);
|
u8* destAddr, int dstWidth, int dstHeight);
|
||||||
|
|
||||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
|
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
|
||||||
|
|
|
@ -488,7 +488,7 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle &source_rect)
|
void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect)
|
||||||
{
|
{
|
||||||
DVSTARTPROFILE();
|
DVSTARTPROFILE();
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
|
@ -682,24 +682,9 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (bCopyToTarget) {
|
|
||||||
// _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
|
|
||||||
// glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
|
||||||
// GL_REPORT_ERRORD();
|
|
||||||
// glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, source->left, source->top, source->right-source->left, source->bottom-source->top);
|
|
||||||
// entry.isUpsideDown = true; // note that the copy is upside down!!
|
|
||||||
// GL_REPORT_ERRORD();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
TRectangle scaled_rect;
|
|
||||||
source_rect.Scale(Renderer::GetTargetScaleX(), Renderer::GetTargetScaleY(), &scaled_rect);
|
|
||||||
TRectangle flipped_rect;
|
|
||||||
scaled_rect.FlipY(Renderer::GetTargetHeight(), &flipped_rect);
|
|
||||||
|
|
||||||
// Make sure to resolve anything we need to read from.
|
// Make sure to resolve anything we need to read from.
|
||||||
// TODO - it seems that it sometimes doesn't resolve the entire area we are interested in. See shadows in Burnout 2.
|
// TODO - it seems that it sometimes doesn't resolve the entire area we are interested in. See shadows in Burnout 2.
|
||||||
GLuint read_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(scaled_rect) : Renderer::ResolveAndGetRenderTarget(scaled_rect);
|
GLuint read_texture = bFromZBuffer ? Renderer::ResolveAndGetDepthTarget(source_rect) : Renderer::ResolveAndGetRenderTarget(source_rect);
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
|
|
||||||
|
@ -727,11 +712,13 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
|
||||||
PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation
|
PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
|
|
||||||
|
TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect);
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glTexCoord2f((GLfloat)flipped_rect.left, (GLfloat)flipped_rect.bottom); glVertex2f(-1, 1);
|
glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1);
|
||||||
glTexCoord2f((GLfloat)flipped_rect.left, (GLfloat)flipped_rect.top ); glVertex2f(-1, -1);
|
glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1);
|
||||||
glTexCoord2f((GLfloat)flipped_rect.right, (GLfloat)flipped_rect.top ); glVertex2f( 1, -1);
|
glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1);
|
||||||
glTexCoord2f((GLfloat)flipped_rect.right, (GLfloat)flipped_rect.bottom); glVertex2f( 1, 1);
|
glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
|
@ -751,10 +738,6 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
|
||||||
{
|
{
|
||||||
static int count = 0;
|
static int count = 0;
|
||||||
SaveTexture(StringFromFormat("%s/efb_frame_%i.tga", FULL_DUMP_TEXTURES_DIR, count++).c_str(), GL_TEXTURE_RECTANGLE_ARB, entry.texture, entry.w, entry.h);
|
SaveTexture(StringFromFormat("%s/efb_frame_%i.tga", FULL_DUMP_TEXTURES_DIR, count++).c_str(), GL_TEXTURE_RECTANGLE_ARB, entry.texture, entry.w, entry.h);
|
||||||
//TODO: Fix this
|
|
||||||
//SaveTexture(StringFromFormat("%s/efb_tex_%i.tga", FULL_DUMP_TEXTURES_DIR, --count).c_str(), GL_TEXTURE_RECTANGLE_ARB,
|
|
||||||
// bFromZBuffer ? Renderer::ResolveAndGetFakeZTarget(source_rect) : Renderer::ResolveAndGetRenderTarget(source_rect),
|
|
||||||
// Renderer::GetTargetWidth() * 2, Renderer::GetTargetHeight() * 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
static void InvalidateRange(u32 start_address, u32 size);
|
static void InvalidateRange(u32 start_address, u32 size);
|
||||||
|
|
||||||
static TCacheEntry* Load(int texstage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt);
|
static TCacheEntry* Load(int texstage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt);
|
||||||
static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle &source);
|
static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source);
|
||||||
|
|
||||||
static void DisableStage(int stage); // sets active texture
|
static void DisableStage(int stage); // sets active texture
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,8 @@
|
||||||
#include "Render.h"
|
#include "Render.h"
|
||||||
#include "TextureConverter.h"
|
#include "TextureConverter.h"
|
||||||
|
|
||||||
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
||||||
{
|
{
|
||||||
TRectangle renderSrcRc;
|
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc);
|
||||||
renderSrcRc.left = sourceRc.left;
|
TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, dstWd, dstHt);
|
||||||
renderSrcRc.right = sourceRc.right;
|
|
||||||
// OpenGL upside down as usual...
|
|
||||||
renderSrcRc.top = Renderer::GetTargetHeight() - sourceRc.top;
|
|
||||||
renderSrcRc.bottom = Renderer::GetTargetHeight() - sourceRc.bottom;
|
|
||||||
TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), renderSrcRc, xfb_in_ram, dstWd, dstHt);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
#ifndef _XFB_H_
|
#ifndef _XFB_H_
|
||||||
#define _XFB_H_
|
#define _XFB_H_
|
||||||
|
|
||||||
|
#include "GLUtil.h"
|
||||||
|
|
||||||
// write the EFB to the XFB
|
// write the EFB to the XFB
|
||||||
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt);
|
void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt);
|
||||||
|
|
||||||
#endif // _XFB_H_
|
#endif // _XFB_H_
|
||||||
|
|
|
@ -523,55 +523,7 @@ void VideoFifo_CheckEFBAccess()
|
||||||
{
|
{
|
||||||
s_efbAccessRequested = FALSE;
|
s_efbAccessRequested = FALSE;
|
||||||
|
|
||||||
switch (s_accessEFBArgs.type)
|
s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y);
|
||||||
{
|
|
||||||
case PEEK_Z:
|
|
||||||
{
|
|
||||||
u32 z = 0;
|
|
||||||
float xScale = Renderer::GetTargetScaleX();
|
|
||||||
float yScale = Renderer::GetTargetScaleY();
|
|
||||||
|
|
||||||
if (g_Config.iMultisampleMode != MULTISAMPLE_OFF)
|
|
||||||
{
|
|
||||||
// Find the proper dimensions
|
|
||||||
TRectangle source, scaledTargetSource;
|
|
||||||
ComputeBackbufferRectangle(&source);
|
|
||||||
source.Scale(xScale, yScale, &scaledTargetSource);
|
|
||||||
// This will resolve and bind to the depth buffer
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Renderer::ResolveAndGetDepthTarget(scaledTargetSource));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the z value! Also adjust the pixel to read to the upscaled EFB resolution
|
|
||||||
// Plus we need to flip the y value as the OGL image is upside down
|
|
||||||
glReadPixels(s_accessEFBArgs.x*xScale, Renderer::GetTargetHeight() - s_accessEFBArgs.y*yScale, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// Clamp the 32bits value returned by glReadPixels to a 24bits value (GC uses a 24bits Z-Buffer)
|
|
||||||
s_AccessEFBResult = z / 0x100;
|
|
||||||
|
|
||||||
// We should probably re-bind the old fbo here.
|
|
||||||
if (g_Config.iMultisampleMode != MULTISAMPLE_OFF) {
|
|
||||||
Renderer::SetFramebuffer(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case POKE_Z:
|
|
||||||
// TODO: Implement
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PEEK_COLOR:
|
|
||||||
// TODO: Implement
|
|
||||||
s_AccessEFBResult = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case POKE_COLOR:
|
|
||||||
// TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
|
|
||||||
// the exact location. Note: EFB pokes are susceptible to Z-buffering
|
|
||||||
// and perhaps blending.
|
|
||||||
//WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_efbResponseEvent.Set();
|
s_efbResponseEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue