// 32 bit frames have additional constraints to frame // maxpos was maximum length of frame at normal constraints inline void VB::CheckFrame32bitRes(int maxpos) { int fbh = frame.fbh; if (frame.fbh >= 512) { // neopets hack maxmin = min(maxmin, frame.fbh); frame.fbh = maxmin; ConstraintReason = 8; } // ffxii hack to stop resolving if (frame.fbp >= 0x3000 && fbh >= 0x1a0) { int endfbp = frame.fbp + frame.fbw * fbh / (PSMT_ISHALF(gsfb.psm) ? 128 : 64); // see if there is a previous render target in the way, reduce for (CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { if (itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp) { endfbp = itnew->second->fbp; } } frame.fbh = (endfbp - frame.fbp) * (PSMT_ISHALF(gsfb.psm) ? 128 : 64) / frame.fbw; if (frame.fbh < fbh) ConstraintReason = 9; } }
inline bool CheckWidthIsSame(const frameInfo& frame, CRenderTarget* ptarg) { if (PSMT_ISHALF(frame.psm) == PSMT_ISHALF(ptarg->psm)) return (frame.fbw == ptarg->fbw); if (PSMT_ISHALF(frame.psm)) return (frame.fbw == 2 * ptarg->fbw); else return (2 * frame.fbw == ptarg->fbw); }
// Check if after resizing, a new render target is needed to be used. Also perform deptarget check. // Returns 1 if only 1 render target is changed and 3 -- if both. inline int VB::CheckFrameResolveRender(int tbp) { int result = 0; CRenderTarget* pprevrndr = prndr; prndr = NULL; CDepthTarget* pprevdepth = pdepth; pdepth = NULL; // Set renderes to NULL to prevent Flushing. CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); assert(pnewtarg != NULL); // pnewtarg->fbh >= 0x1c0 needed for ffx if ((pnewtarg->fbh >= 0x1c0) && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk) { // check if zbuf is in the way of the texture (suikoden5) int maxallowedfbh = (tbp - zbuf.zbp) * (PSMT_ISHALF(zbuf.psm) ? 128 : 64) / gsfb.fbw; if (PSMT_ISHALF(gsfb.psm)) maxallowedfbh *= 2; if (pnewtarg->fbh > maxallowedfbh + 32) // +32 needed for ffx2 { // destroy and recreate s_RTs.DestroyAllTargs(0, 0x100, pnewtarg->fbw); pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); assert(pnewtarg != NULL); } } ZZLog::Prim_Log("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); if ((pprevrndr != pnewtarg) || (pprevrndr != NULL && (pprevrndr->status & CRenderTarget::TS_NeedUpdate))) result = 1; prndr = pnewtarg; pdepth = pprevdepth; result |= CheckFrameResolveDepth(tbp); return result; }
// Return number of 64-pixels block, that guaranted could be hold in memory // from gsfb.fbp and tbp (textrure pase), zbuf.zbp (Z-buffer), frame.fbp // (previous frame). inline int VB::FindMinimalMemoryConstrain(int tbp, int maxpos) { int MinConstraint = maxpos; // make sure texture is far away from tbp { int Constraint = tbp - gsfb.fbp; if ((0 < Constraint) && (Constraint < MinConstraint)) { MinConstraint = Constraint; ConstraintReason = 1; } } // offroad uses 0x80 fbp which messes up targets // special case when double buffering (hamsterball) // Suikoden 3 require e00 have this issue too. P3 - 0x1000. if (prndr != NULL) { int Constraint = frame.fbp - gsfb.fbp; if ((0x0 < Constraint) && (Constraint < MinConstraint)) { MinConstraint = Constraint; ConstraintReason = 2; } } // old caching method // zmsk necessary for KH movie if (!zbuf.zmsk) { int Constraint = zbuf.zbp - gsfb.fbp; if ((0 < Constraint) && (Constraint < MinConstraint)) { MinConstraint = Constraint; ConstraintReason = 3; } } // In 16Bit mode in one Word frame stored 2 pixels if (PSMT_ISHALF(gsfb.psm)) MinConstraint *= 2; return MinConstraint ; }
// This is the main code for frame resizing. // It checks for several reasons to resize and resizes if it needs to. // 4Mb memory in 64 bit (4 bytes) words. // |------------------------|---------------------|----------|----------|---------------------| // 0 gsfb.fbp zbuff.zpb tbp frame.fbp 2^20/64 inline int VB::CheckFrameAddConstraints(int tbp) { if (gsfb.fbw <= 0) { ERROR_LOG_SPAM("render target null, no constraints. Ignoring\n"); return -1; } // Memory region after fbp int maxmemorypos = 0x4000 - gsfb.fbp; ConstraintReason = 0; maxmemorypos = FindMinimalMemoryConstrain(tbp, maxmemorypos); maxmemorypos = FindZbufferMemoryConstrain(tbp, maxmemorypos); int maxpos = 64 * maxmemorypos ; maxpos /= gsfb.fbw; //? atelier iris crashes without it if (maxpos > 256) maxpos &= ~0x1f; #ifdef DEVBUILD int noscissorpos = maxpos; int ConstrainR1 = ConstraintReason; #endif maxpos = FindMinimalHeightConstrain(maxpos); frame = gsfb; frame.fbh = maxpos; if (!PSMT_ISHALF(frame.psm) || !(conf.settings().full_16_bit_res)) CheckFrame32bitRes(maxpos); #ifdef DEVBUILD if (frame.fbh == 0xe2) ZZLog::Debug_Log("Const: %x %x %d| %x %d %x %x", frame.fbh, frame.fbw, ConstraintReason, noscissorpos, ConstrainR1, tbp, frame.fbp); #endif // Fixme: Reserved psm for framebuffers // gsfb.psm &= 0xf; // shadow tower return 0; }
// Return number of 64 pizel words that could be placed in Z-Buffer // If no Z-buffer present return old constraint inline int VB::FindZbufferMemoryConstrain(int tbp, int maxpos) { int MinConstraint = maxpos; // Check tbp / zbuffer constraint if (!zbuf.zmsk) { int Constraint = (tbp - zbuf.zbp) * (PSMT_ISHALF(zbuf.psm) ? 2 : 1); if ((0 < Constraint) && (Constraint < MinConstraint)) { MinConstraint = Constraint; ConstraintReason = 4; } } return MinConstraint; }
void CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) { FUNCLOG int dy = 0; if (fbplocal != fbp) { float4 v; // will be rendering to a subregion u32 bpp = PSMT_ISHALF(psm) ? 2 : 4; assert(((256 / bpp)*(fbplocal - fbp)) % fbw == 0); assert(fbplocal >= fbp); dy = ((256 / bpp) * (fbplocal - fbp)) / fbw; v.x = vposxy.x; v.y = vposxy.y; v.z = vposxy.z; v.w = vposxy.w - dy * 2.0f / (float)fbh; ZZshSetParameter4fv(g_vparamPosXY[context], v, "g_fPosXY"); } else { ZZshSetParameter4fv(g_vparamPosXY[context], vposxy, "g_fPosXY"); } // set render states // Bleh. I *really* need to fix this. << 3 when setting the scissors, then >> 3 when using them... --Arcum42 scissorrect.x = scissor.x0 >> 3; scissorrect.y = (scissor.y0 >> 3) + dy; scissorrect.w = (scissor.x1 >> 3) + 1; scissorrect.h = (scissor.y1 >> 3) + 1 + dy; scissorrect.w = min(scissorrect.w, fbw) - scissorrect.x; scissorrect.h = min(scissorrect.h, fbh) - scissorrect.y; scissorrect.x = RW(scissorrect.x); scissorrect.y = RH(scissorrect.y); scissorrect.w = RW(scissorrect.w); scissorrect.h = RH(scissorrect.h); }