Path: blob/master/GPU/Common/FramebufferManagerCommon.h
5658 views
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617// TODO: We now have the tools in thin3d to nearly eliminate the backend-specific framebuffer managers.18// Here's a list of functionality to unify into FramebufferManagerCommon:19// * DrawActiveTexture20// * BlitFramebuffer21//22// Also, in TextureCache we should be able to unify texture-based depal.2324#pragma once2526#include <vector>27#include <unordered_map>2829#include "Common/CommonTypes.h"30#include "Common/Log.h"31#include "Common/GPU/thin3d.h"32#include "Core/Config.h"33#include "Core/ConfigValues.h"34#include "GPU/GPU.h"35#include "GPU/GPUDefinitions.h"36#include "GPU/ge_constants.h"37#include "GPU/Common/Draw2D.h"3839enum {40FB_USAGE_DISPLAYED_FRAMEBUFFER = 1,41FB_USAGE_RENDER_COLOR = 2,42FB_USAGE_TEXTURE = 4,43FB_USAGE_CLUT = 8,44FB_USAGE_DOWNLOAD = 16,45FB_USAGE_DOWNLOAD_CLEAR = 32,46FB_USAGE_BLUE_TO_ALPHA = 64,47FB_USAGE_FIRST_FRAME_SAVED = 128,48FB_USAGE_RENDER_DEPTH = 256,49FB_USAGE_COLOR_MIXED_DEPTH = 512,50FB_USAGE_INVALIDATE_DEPTH = 1024, // used to clear depth buffers.51};5253enum {54FB_NON_BUFFERED_MODE = 0,55FB_BUFFERED_MODE = 1,56};5758namespace Draw {59class Framebuffer;60}6162class VulkanFBO;63class ShaderWriter;6465// We have to track VFBs and depth buffers together, since bits are shared between the color alpha channel66// and the stencil buffer on the PSP.67// Sometimes, virtual framebuffers need to share a Z buffer. We emulate this by copying from on to the next68// when such a situation is detected. In order to reliably detect this, we separately track depth buffers,69// and they know which color buffer they were used with last.70// Two VirtualFramebuffer can occupy the same address range as long as they have different fb_format.71// In that case, the one with the highest colorBindSeq number is the valid one.72struct VirtualFramebuffer {73u32 fb_address;74u32 z_address; // If 0, it's a "RAM" framebuffer.75u16 fb_stride;76u16 z_stride;7778// The original PSP format of the framebuffer.79// In reality they are all RGBA8888 for better quality but this is what the PSP thinks it is. This is necessary80// when we need to interpret the bits directly (depal or buffer aliasing).81// NOTE: CANNOT be changed after creation anymore!82GEBufferFormat fb_format;8384Draw::Framebuffer *fbo;8586// width/height: The detected size of the current framebuffer, in original PSP pixels.87u16 width;88u16 height;8990// bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than or equal to width/height.91// In original PSP pixels - actual framebuffer is this size times the render resolution multiplier.92// The buffer may be used to render a width or height from 0 to these values without being recreated.93u16 bufferWidth;94u16 bufferHeight;9596// renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions.97// These are simply bufferWidth/Height * renderScaleFactor and are thus redundant.98u16 renderWidth;99u16 renderHeight;100101// Attempt to keep track of a bounding rectangle of what's been actually drawn. Coarse, but might be smaller102// than width/height if framebuffer has been enlarged. In PSP pixels.103u16 drawnWidth;104u16 drawnHeight;105106// The dimensions at which we are confident that we can read back this buffer without stomping on irrelevant memory.107u16 safeWidth;108u16 safeHeight;109110// The scale factor at which we are rendering (to achieve higher resolution).111u8 renderScaleFactor;112113u16 usageFlags;114115// These are used to track state to try to avoid buffer size shifting back and forth.116// You might think that doesn't happen since we mostly grow framebuffers, but we do resize down,117// if the size has shrunk for a while and the framebuffer is also larger than the stride.118// At this point, the "safe" size is probably a lie, and we have had various issues with readbacks, so this resizes down to avoid them.119// An example would be a game that always uses the address 0x00154000 for temp buffers, and uses it for a full-screen effect for 3 frames, then goes back to using it for character shadows or something much smaller.120u16 newWidth;121u16 newHeight;122123// The frame number at which this was last resized.124int lastFrameNewSize;125126// Tracking for downloads-to-CLUT.127u16 clutUpdatedBytes;128129// Means that the whole image has already been read back to memory - used when combining small readbacks (gameUsesSequentialCopies_).130bool memoryUpdated;131132// TODO: Fold into usageFlags?133bool dirtyAfterDisplay;134bool reallyDirtyAfterDisplay; // takes frame skipping into account135136// Global sequence numbers for the last time these were bound.137// Not based on frames at all. Can be used to determine new-ness of one framebuffer over another,138// can even be within a frame.139int colorBindSeq;140int depthBindSeq;141142// These are mainly used for garbage collection purposes and similar.143// Cannot be used to determine new-ness against a similar other buffer, since they are144// only at frame granularity.145int last_frame_used;146int last_frame_attached;147int last_frame_render;148int last_frame_displayed;149int last_frame_clut;150int last_frame_failed;151int last_frame_depth_updated;152int last_frame_depth_render;153154// Convenience methods155inline int WidthInBytes() const { return width * BufferFormatBytesPerPixel(fb_format); }156inline int BufferWidthInBytes() const { return bufferWidth * BufferFormatBytesPerPixel(fb_format); }157inline int FbStrideInBytes() const { return fb_stride * BufferFormatBytesPerPixel(fb_format); }158inline int ZStrideInBytes() const { return z_stride * 2; }159160inline int Stride(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_stride : z_stride; }161inline u32 Address(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_address : z_address; }162inline GEBufferFormat Format(RasterChannel channel) const { return channel == RASTER_COLOR ? fb_format : GE_FORMAT_DEPTH16; }163inline int BindSeq(RasterChannel channel) const { return channel == RASTER_COLOR ? colorBindSeq : depthBindSeq; }164165// Computed from stride.166int BufferByteSize(RasterChannel channel) const { return BufferByteStride(channel) * height; }167int BufferByteStride(RasterChannel channel) const {168return channel == RASTER_COLOR ? fb_stride * (fb_format == GE_FORMAT_8888 ? 4 : 2) : z_stride * 2;169}170int BufferByteWidth(RasterChannel channel) const {171return channel == RASTER_COLOR ? width * (fb_format == GE_FORMAT_8888 ? 4 : 2) : width * 2;172}173};174175struct FramebufferHeuristicParams {176u32 fb_address;177u32 z_address;178u16 fb_stride;179u16 z_stride;180GEBufferFormat fb_format;181bool isClearingDepth;182bool isWritingDepth;183bool isDrawing;184bool isModeThrough;185bool isBlending;186int viewportWidth;187int viewportHeight;188int16_t regionWidth;189int16_t regionHeight;190int16_t scissorLeft;191int16_t scissorTop;192int16_t scissorRight;193int16_t scissorBottom;194};195196struct GPUgstate;197extern GPUgstate gstate;198199void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate);200201enum BindFramebufferColorFlags {202BINDFBCOLOR_SKIP_COPY = 0,203BINDFBCOLOR_MAY_COPY = 1,204BINDFBCOLOR_MAY_COPY_WITH_UV = 3, // includes BINDFBCOLOR_MAY_COPY205BINDFBCOLOR_APPLY_TEX_OFFSET = 4,206// Used when rendering to a temporary surface (e.g. not the current render target.)207BINDFBCOLOR_FORCE_SELF = 8,208BINDFBCOLOR_UNCACHED = 16,209};210211enum DrawTextureFlags {212DRAWTEX_NEAREST = 0,213DRAWTEX_LINEAR = 1,214DRAWTEX_TO_BACKBUFFER = 8,215DRAWTEX_DEPTH = 16,216};217218inline DrawTextureFlags operator | (const DrawTextureFlags &lhs, const DrawTextureFlags &rhs) {219return DrawTextureFlags((u32)lhs | (u32)rhs);220}221222enum class TempFBO {223DEPAL,224BLIT,225// For copies of framebuffers (e.g. shader blending.)226COPY,227// Used for copies when setting color to depth.228Z_COPY,229// Used to copy stencil data, means we need a stencil backing.230STENCIL,231};232233inline Draw::DataFormat GEFormatToThin3D(GEBufferFormat geFormat) {234switch (geFormat) {235case GE_FORMAT_4444:236return Draw::DataFormat::A4R4G4B4_UNORM_PACK16;237case GE_FORMAT_5551:238return Draw::DataFormat::A1R5G5B5_UNORM_PACK16;239case GE_FORMAT_565:240return Draw::DataFormat::R5G6B5_UNORM_PACK16;241case GE_FORMAT_8888:242return Draw::DataFormat::R8G8B8A8_UNORM;243case GE_FORMAT_DEPTH16:244return Draw::DataFormat::D16;245default:246// TODO: Assert?247return Draw::DataFormat::UNDEFINED;248}249}250251// Dimensions are in bytes, later steps get to convert back into real coordinates as appropriate.252// Makes it easy to see if blits match etc.253struct BlockTransferRect {254VirtualFramebuffer *vfb;255RasterChannel channel; // We usually only deal with color, but we have limited depth block transfer support now.256257int x_bytes;258int y;259int w_bytes;260int h;261262std::string ToString() const;263264int w_pixels() const {265return w_bytes / BufferFormatBytesPerPixel(vfb->fb_format);266}267int x_pixels() const {268return x_bytes / BufferFormatBytesPerPixel(vfb->fb_format);269}270};271272namespace Draw {273class DrawContext;274}275276struct DrawPixelsEntry {277Draw::Texture *tex;278uint64_t contentsHash;279int frameNumber;280};281282struct GPUDebugBuffer;283class DrawEngineCommon;284class PresentationCommon;285class ShaderManagerCommon;286class TextureCacheCommon;287struct DisplayLayoutConfig;288289class FramebufferManagerCommon {290public:291FramebufferManagerCommon(Draw::DrawContext *draw);292virtual ~FramebufferManagerCommon();293294void SetTextureCache(TextureCacheCommon *tc) {295textureCache_ = tc;296}297void SetShaderManager(ShaderManagerCommon * sm) {298shaderManager_ = sm;299}300void SetDrawEngine(DrawEngineCommon *td) {301drawEngine_ = td;302}303304void Init(int msaaLevel);305virtual void BeginFrame(const DisplayLayoutConfig &config);306void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format);307void DestroyFramebuf(VirtualFramebuffer *v);308309VirtualFramebuffer *DoSetRenderFrameBuffer(FramebufferHeuristicParams ¶ms, u32 skipDrawReason);310VirtualFramebuffer *SetRenderFrameBuffer(bool framebufChanged, int skipDrawReason, bool *changed) {311// Inlining this part since it's so frequent.312if (!framebufChanged && currentRenderVfb_) {313currentRenderVfb_->last_frame_render = gpuStats.numFlips;314currentRenderVfb_->dirtyAfterDisplay = true;315if (!skipDrawReason)316currentRenderVfb_->reallyDirtyAfterDisplay = true;317*changed = false;318return currentRenderVfb_;319} else {320// This is so that we will be able to drive DoSetRenderFramebuffer with inputs321// that come from elsewhere than gstate.322FramebufferHeuristicParams inputs;323GetFramebufferHeuristicInputs(&inputs, gstate);324VirtualFramebuffer *vfb = DoSetRenderFrameBuffer(inputs, skipDrawReason);325_dbg_assert_msg_(vfb, "DoSetRenderFramebuffer must return a valid framebuffer.");326_dbg_assert_msg_(currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer.");327*changed = true;328return vfb;329}330}331void SetDepthFrameBuffer(bool isClearingDepth);332333void RebindFramebuffer(const char *tag);334std::vector<const VirtualFramebuffer *> GetFramebufferList() const;335336void CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty);337338bool NotifyFramebufferCopy(u32 src, u32 dest, int size, GPUCopyFlag flags, u32 skipDrawReason);339void PerformWriteFormattedFromMemory(u32 addr, int size, int width, GEBufferFormat fmt);340void UpdateFromMemory(u32 addr, int size);341void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);342bool PerformWriteStencilFromMemory(u32 addr, int size, WriteStencil flags);343344// We changed our depth mode, gotta start over.345// Ideally, we should convert depth buffers here, not just clear them.346void ClearAllDepthBuffers();347348// Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it.349// In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless350// read framebuffers is on, in which case this should always return false).351// If this returns false, a memory copy will happen and NotifyBlockTransferAfter will be called.352bool NotifyBlockTransferBefore(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);353354// This gets called after the memory copy, in case NotifyBlockTransferBefore returned false.355// Otherwise it doesn't get called.356void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);357358bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer);359void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode);360361void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);362bool DrawFramebufferToOutput(const DisplayLayoutConfig &config, const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat);363364// TODO: Should split into one that uses config, and one that doesn't.365void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, RasterChannel channel, const char *tag);366367size_t NumVFBs() const { return vfbs_.size(); }368369u32 PrevDisplayFramebufAddr() const {370return prevDisplayFramebuf_ ? prevDisplayFramebuf_->fb_address : 0;371}372u32 CurrentDisplayFramebufAddr() const {373return displayFramebuf_ ? displayFramebuf_->fb_address : 0;374}375376u32 DisplayFramebufAddr() const {377return displayFramebufPtr_;378}379u32 DisplayFramebufStride() const {380return displayStride_;381}382GEBufferFormat DisplayFramebufFormat() const {383return displayFormat_;384}385386bool UseBufferedRendering() const {387return useBufferedRendering_;388}389390void ForceUseBufferedRendering(bool buf) {391useBufferedRendering_ = true;392}393394// TODO: Maybe just include the last depth buffer address in this, too.395bool MayIntersectFramebufferColor(u32 start) const {396// Clear the cache/kernel bits.397start &= 0x3FFFFFFF;398if (Memory::IsVRAMAddress(start))399start &= 0x041FFFFF;400// Most games only have two framebuffers at the start.401if (start >= framebufColorRangeEnd_ || start < PSP_GetVidMemBase()) {402return false;403}404return true;405}406407VirtualFramebuffer *GetCurrentRenderVFB() const {408return currentRenderVfb_;409}410411// This only checks for the color channel, and if there are multiple overlapping ones412// with different color depth, this might get things wrong.413// DEPRECATED FOR NEW USES - avoid whenever possible.414VirtualFramebuffer *GetVFBAt(u32 addr) const;415416// This will only return exact matches of addr+stride+format.417VirtualFramebuffer *GetExactVFB(u32 addr, int stride, GEBufferFormat format) const;418419// If this doesn't find the exact VFB, but one with a different color format with matching stride,420// it'll resolve the newest one at address to the format requested, and return that.421VirtualFramebuffer *ResolveVFB(u32 addr, int stride, GEBufferFormat format);422423// Utility to get the display VFB.424VirtualFramebuffer *GetDisplayVFB();425426int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; }427int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; }428int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; }429int GetTargetHeight() const { return currentRenderVfb_ ? currentRenderVfb_->height : 272; }430int GetTargetBufferWidth() const { return currentRenderVfb_ ? currentRenderVfb_->bufferWidth : 480; }431int GetTargetBufferHeight() const { return currentRenderVfb_ ? currentRenderVfb_->bufferHeight : 272; }432int GetTargetStride() const { return currentRenderVfb_ ? currentRenderVfb_->fb_stride : 512; }433GEBufferFormat GetTargetFormat() const { return currentRenderVfb_ ? currentRenderVfb_->fb_format : displayFormat_; }434435void SetColorUpdated(int skipDrawReason) {436if (currentRenderVfb_) {437SetColorUpdated(currentRenderVfb_, skipDrawReason);438}439}440void SetSafeSize(u16 w, u16 h);441442void NotifyRenderResized(const DisplayLayoutConfig &config, int msaaLevel);443virtual void NotifyDisplayResized();444void NotifyConfigChanged();445446void CheckPostShaders(const DisplayLayoutConfig &config);447448virtual void DestroyAllFBOs();449450virtual void DeviceLost();451virtual void DeviceRestore(Draw::DrawContext *draw);452453Draw::Framebuffer *GetTempFBO(TempFBO reason, u16 w, u16 h);454455// Debug features456virtual bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);457virtual bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer);458virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer);459virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer);460461const std::vector<VirtualFramebuffer *> &Framebuffers() const {462return vfbs_;463}464465Draw2D *GetDraw2D() {466return &draw2D_;467}468469// If a vfb with the target format exists, resolve it (run CopyToColorFromOverlappingFramebuffers).470// If it doesn't exist, create it and do the same.471// Returns the resolved framebuffer.472VirtualFramebuffer *ResolveFramebufferColorToFormat(VirtualFramebuffer *vfb, GEBufferFormat newFormat);473474Draw2DPipeline *Get2DPipeline(Draw2DShader shader);475476// If from==to, returns a copy pipeline.477Draw2DPipeline *GetReinterpretPipeline(GEBufferFormat from, GEBufferFormat to, float *scaleFactorX);478479// Public to be used from the texture cache's depal shenanigans.480void BlitUsingRaster(481Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2,482Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2,483bool linearFilter,484int scaleFactor, // usually unused, except for swizzle...485Draw2DPipeline *pipeline, const char *tag);486487void ReleasePipelines();488489int GetMSAALevel() const {490return msaaLevel_;491}492493void DiscardFramebufferCopy() {494currentFramebufferCopy_ = nullptr;495}496497bool PresentedThisFrame() const;498499const std::vector<VirtualFramebuffer *> &GetVFBs() const {500return vfbs_;501}502503// Hack, only needed for non-buffered rendering.504const DisplayLayoutConfig &GetDisplayLayoutConfigCopy() const {505return displayLayoutConfigCopy_;506}507508protected:509virtual void ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode);510// Used for when a shader is required, such as GLES.511virtual bool ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode);512virtual bool ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride, Draw::ReadbackMode mode);513void SetViewport2D(int x, int y, int w, int h);514Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);515void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags);516517void CopyToColorFromOverlappingFramebuffers(VirtualFramebuffer *dest);518void CopyToDepthFromOverlappingFramebuffers(VirtualFramebuffer *dest);519520bool UpdateRenderSize(int msaaLevel);521522void FlushBeforeCopy();523virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra524525// Used by ReadFramebufferToMemory and later framebuffer block copies526void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, RasterChannel channel, const char *tag);527528void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer, bool *partial);529530void EstimateDrawingSize(u32 fb_address, int fb_stride, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int &drawing_width, int &drawing_height);531532void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb);533static void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb);534void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth);535536void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst, bool allowSizeMismatch = false);537538void ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force = false, bool skipCopy = false);539540static bool ShouldDownloadFramebufferColor(const VirtualFramebuffer *vfb);541static bool ShouldDownloadFramebufferDepth(const VirtualFramebuffer *vfb);542void DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb);543544bool FindTransferFramebuffer(u32 basePtr, int stride, int x, int y, int w, int h, int bpp, bool destination, BlockTransferRect *rect);545546VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb, RasterChannel channel);547virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {}548549VirtualFramebuffer *CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format);550551void UpdateFramebufUsage(VirtualFramebuffer *vfb) const;552553int GetFramebufferLayers() const;554555static void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) {556dstBuffer->memoryUpdated = false;557dstBuffer->clutUpdatedBytes = 0;558dstBuffer->dirtyAfterDisplay = true;559dstBuffer->drawnWidth = dstBuffer->width;560dstBuffer->drawnHeight = dstBuffer->height;561if ((skipDrawReason & SKIPDRAW_SKIPFRAME) == 0)562dstBuffer->reallyDirtyAfterDisplay = true;563}564565inline int GetBindSeqCount() {566return fbBindSeqCount_++;567}568569static SkipGPUReadbackMode GetSkipGPUReadbackMode();570571PresentationCommon *presentation_ = nullptr;572573Draw::DrawContext *draw_ = nullptr;574575TextureCacheCommon *textureCache_ = nullptr;576ShaderManagerCommon *shaderManager_ = nullptr;577DrawEngineCommon *drawEngine_ = nullptr;578579bool needBackBufferYSwap_ = false;580581u32 displayFramebufPtr_ = 0;582u32 displayStride_ = 0;583GEBufferFormat displayFormat_ = GE_FORMAT_565;584u32 prevDisplayFramebufPtr_ = 0;585586int fbBindSeqCount_ = 0;587588VirtualFramebuffer *displayFramebuf_ = nullptr;589VirtualFramebuffer *prevDisplayFramebuf_ = nullptr;590VirtualFramebuffer *prevPrevDisplayFramebuf_ = nullptr;591int frameLastFramebufUsed_ = 0;592593VirtualFramebuffer *currentRenderVfb_ = nullptr;594595Draw::Framebuffer *currentFramebufferCopy_ = nullptr;596597// The range of PSP memory that may contain FBOs. So we can skip iterating.598u32 framebufColorRangeEnd_ = 0;599600bool useBufferedRendering_ = false;601bool postShaderIsUpscalingFilter_ = false;602bool postShaderIsSupersampling_ = false;603604std::vector<VirtualFramebuffer *> vfbs_;605std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)606607std::vector<DrawPixelsEntry> drawPixelsCache_;608609bool gameUsesSequentialCopies_ = false;610611// Sampled in BeginFrame/UpdateSize for safety.612float renderWidth_ = 0.0f;613float renderHeight_ = 0.0f;614615int msaaLevel_ = 0;616int renderScaleFactor_ = 1;617int pixelWidth_ = 0;618int pixelHeight_ = 0;619int bloomHack_ = 0;620bool updatePostShaders_ = false;621622Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM;623624struct TempFBOInfo {625Draw::Framebuffer *fbo;626int last_frame_used;627};628629std::unordered_map<u64, TempFBOInfo> tempFBOs_;630631std::vector<Draw::Framebuffer *> fbosToDelete_;632633// Aggressively delete unused FBOs to save gpu memory.634enum {635FBO_OLD_AGE = 5,636FBO_OLD_USAGE_FLAG = 15,637};638639// Thin3D stuff for reinterpreting image data between the various 16-bit color formats.640// Safe, not optimal - there might be input attachment tricks, etc, but we can't use them641// since we don't want N different implementations.642Draw2DPipeline *reinterpretFromTo_[4][4]{};643644// Common implementation of stencil buffer upload. Also not 100% optimal, but not performance645// critical either.646Draw::Pipeline *stencilWritePipeline_ = nullptr;647Draw::SamplerState *stencilWriteSampler_ = nullptr;648649// Used on GLES where we can't directly readback depth or stencil, but here for simplicity.650Draw::Pipeline *stencilReadbackPipeline_ = nullptr;651Draw::SamplerState *stencilReadbackSampler_ = nullptr;652Draw::Pipeline *depthReadbackPipeline_ = nullptr;653Draw::SamplerState *depthReadbackSampler_ = nullptr;654655// Draw2D pipelines656Draw2DPipeline *draw2DPipelineCopyColor_ = nullptr;657Draw2DPipeline *draw2DPipelineColorRect2Lin_ = nullptr;658Draw2DPipeline *draw2DPipelineCopyDepth_ = nullptr;659Draw2DPipeline *draw2DPipelineEncodeDepth_ = nullptr;660Draw2DPipeline *draw2DPipeline565ToDepth_ = nullptr;661Draw2DPipeline *draw2DPipeline565ToDepthDeswizzle_ = nullptr;662663Draw2D draw2D_;664// The fragment shaders are "owned" by the pipelines since they're 1:1.665666// Depth readback helper state667u8 *convBuf_ = nullptr;668u32 convBufSize_ = 0;669670DisplayLayoutConfig displayLayoutConfigCopy_{};671};672673// Should probably live elsewhere.674bool GetOutputFramebuffer(Draw::DrawContext *draw, GPUDebugBuffer &buffer);675676677