1 // Copyright (c) 2012- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18 // TODO: We now have the tools in thin3d to nearly eliminate the backend-specific framebuffer managers.
19 // Here's a list of functionality to unify into FramebufferManagerCommon:
20 // * DrawActiveTexture
21 // * BlitFramebuffer
22 // * StencilBuffer*.cpp
23 //
24 // Also, in TextureCache we should be able to unify texture-based depal.
25
26 #pragma once
27
28 #include <set>
29 #include <vector>
30 #include <unordered_map>
31
32 #include "Common/CommonTypes.h"
33 #include "Common/Log.h"
34 #include "Core/MemMap.h"
35 #include "GPU/GPU.h"
36 #include "GPU/ge_constants.h"
37 #include "GPU/GPUInterface.h"
38 #include "Common/GPU/thin3d.h"
39
40 enum {
41 FB_USAGE_DISPLAYED_FRAMEBUFFER = 1,
42 FB_USAGE_RENDERTARGET = 2,
43 FB_USAGE_TEXTURE = 4,
44 FB_USAGE_CLUT = 8,
45 FB_USAGE_DOWNLOAD = 16,
46 FB_USAGE_DOWNLOAD_CLEAR = 32,
47 };
48
49 enum {
50 FB_NON_BUFFERED_MODE = 0,
51 FB_BUFFERED_MODE = 1,
52 };
53
54 namespace Draw {
55 class Framebuffer;
56 }
57
58 class VulkanFBO;
59
60 struct VirtualFramebuffer {
61 u32 fb_address;
62 u32 z_address; // If 0, it's a "RAM" framebuffer.
63 int fb_stride;
64 int z_stride;
65
66 GEBufferFormat format; // virtual, in reality they are all RGBA8888 for better quality but we can reinterpret that as necessary
67
68 // width/height: The detected size of the current framebuffer, in original PSP pixels.
69 u16 width;
70 u16 height;
71
72 // bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than or equal to width/height.
73 // Actual physical buffer is this size times the render resolution multiplier.
74 // The buffer may be used to render a width or height from 0 to these values without being recreated.
75 u16 bufferWidth;
76 u16 bufferHeight;
77
78 // renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions.
79 // The physical buffer may be larger than renderWidth/renderHeight.
80 u16 renderWidth;
81 u16 renderHeight;
82
83 float renderScaleFactor;
84
85 u16 usageFlags;
86
87 u16 newWidth;
88 u16 newHeight;
89
90 int lastFrameNewSize;
91
92 Draw::Framebuffer *fbo;
93
94 u16 drawnWidth;
95 u16 drawnHeight;
96 GEBufferFormat drawnFormat;
97 u16 safeWidth;
98 u16 safeHeight;
99
100 bool dirtyAfterDisplay;
101 bool reallyDirtyAfterDisplay; // takes frame skipping into account
102
103 int last_frame_used;
104 int last_frame_attached;
105 int last_frame_render;
106 int last_frame_displayed;
107 int last_frame_clut;
108 int last_frame_failed;
109 int last_frame_depth_updated;
110 int last_frame_depth_render;
111 u32 clutUpdatedBytes;
112 bool memoryUpdated;
113 bool firstFrameSaved;
114 };
115
116 struct FramebufferHeuristicParams {
117 u32 fb_address;
118 int fb_stride;
119 u32 z_address;
120 int z_stride;
121 GEBufferFormat fmt;
122 bool isClearingDepth;
123 bool isWritingDepth;
124 bool isDrawing;
125 bool isModeThrough;
126 int viewportWidth;
127 int viewportHeight;
128 int regionWidth;
129 int regionHeight;
130 int scissorWidth;
131 int scissorHeight;
132 };
133
134 struct GPUgstate;
135 extern GPUgstate gstate;
136
137 void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate);
138
139 enum BindFramebufferColorFlags {
140 BINDFBCOLOR_SKIP_COPY = 0,
141 BINDFBCOLOR_MAY_COPY = 1,
142 BINDFBCOLOR_MAY_COPY_WITH_UV = 3, // includes BINDFBCOLOR_MAY_COPY
143 BINDFBCOLOR_APPLY_TEX_OFFSET = 4,
144 // Used when rendering to a temporary surface (e.g. not the current render target.)
145 BINDFBCOLOR_FORCE_SELF = 8,
146 };
147
148 enum DrawTextureFlags {
149 DRAWTEX_NEAREST = 0,
150 DRAWTEX_LINEAR = 1,
151 DRAWTEX_KEEP_STENCIL_ALPHA = 4,
152 DRAWTEX_TO_BACKBUFFER = 8,
153 };
154
155 inline DrawTextureFlags operator | (const DrawTextureFlags &lhs, const DrawTextureFlags &rhs) {
156 return DrawTextureFlags((u32)lhs | (u32)rhs);
157 }
158
159 enum class StencilUpload {
160 NEEDS_CLEAR,
161 STENCIL_IS_ZERO,
162 };
163
164 enum class TempFBO {
165 DEPAL,
166 BLIT,
167 // For copies of framebuffers (e.g. shader blending.)
168 COPY,
169 // For another type of framebuffers that can happen together with COPY (see Outrun)
170 REINTERPRET,
171 // Used to copy stencil data, means we need a stencil backing.
172 STENCIL,
173 };
174
GEFormatToThin3D(int geFormat)175 inline Draw::DataFormat GEFormatToThin3D(int geFormat) {
176 switch (geFormat) {
177 case GE_FORMAT_4444:
178 return Draw::DataFormat::A4R4G4B4_UNORM_PACK16;
179 case GE_FORMAT_5551:
180 return Draw::DataFormat::A1R5G5B5_UNORM_PACK16;
181 case GE_FORMAT_565:
182 return Draw::DataFormat::R5G6B5_UNORM_PACK16;
183 case GE_FORMAT_8888:
184 return Draw::DataFormat::R8G8B8A8_UNORM;
185 default:
186 return Draw::DataFormat::UNDEFINED;
187 }
188 }
189
190 namespace Draw {
191 class DrawContext;
192 }
193
194 struct GPUDebugBuffer;
195 class DrawEngineCommon;
196 class PresentationCommon;
197 class ShaderManagerCommon;
198 class TextureCacheCommon;
199
200 class FramebufferManagerCommon {
201 public:
202 FramebufferManagerCommon(Draw::DrawContext *draw);
203 virtual ~FramebufferManagerCommon();
204
205 virtual void Init();
206 virtual void BeginFrame();
207 void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format);
208 void DestroyFramebuf(VirtualFramebuffer *v);
209
210 VirtualFramebuffer *DoSetRenderFrameBuffer(const FramebufferHeuristicParams ¶ms, u32 skipDrawReason);
SetRenderFrameBuffer(bool framebufChanged,int skipDrawReason)211 VirtualFramebuffer *SetRenderFrameBuffer(bool framebufChanged, int skipDrawReason) {
212 // Inlining this part since it's so frequent.
213 if (!framebufChanged && currentRenderVfb_) {
214 currentRenderVfb_->last_frame_render = gpuStats.numFlips;
215 currentRenderVfb_->dirtyAfterDisplay = true;
216 if (!skipDrawReason)
217 currentRenderVfb_->reallyDirtyAfterDisplay = true;
218 return currentRenderVfb_;
219 } else {
220 // This is so that we will be able to drive DoSetRenderFramebuffer with inputs
221 // that come from elsewhere than gstate.
222 FramebufferHeuristicParams inputs;
223 GetFramebufferHeuristicInputs(&inputs, gstate);
224 VirtualFramebuffer *vfb = DoSetRenderFrameBuffer(inputs, skipDrawReason);
225 _dbg_assert_msg_(vfb, "DoSetRenderFramebuffer must return a valid framebuffer.");
226 _dbg_assert_msg_(currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer.");
227 return vfb;
228 }
229 }
230 void RebindFramebuffer(const char *tag);
231 std::vector<FramebufferInfo> GetFramebufferList();
232
233 void CopyDisplayToOutput(bool reallyDirty);
234
235 bool NotifyFramebufferCopy(u32 src, u32 dest, int size, bool isMemset, u32 skipDrawReason);
236 void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt);
237 void UpdateFromMemory(u32 addr, int size, bool safe);
238 void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);
239 virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0;
240 // Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it.
241 // In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless
242 // read framebuffers is on, in which case this should always return false).
243 bool 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);
244 void 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);
245
246 bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
247 void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h);
248
249 void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
250 void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride);
251
252 void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
253
NumVFBs()254 size_t NumVFBs() const { return vfbs_.size(); }
255
PrevDisplayFramebufAddr()256 u32 PrevDisplayFramebufAddr() {
257 return prevDisplayFramebuf_ ? prevDisplayFramebuf_->fb_address : 0;
258 }
DisplayFramebufAddr()259 u32 DisplayFramebufAddr() {
260 return displayFramebuf_ ? displayFramebuf_->fb_address : 0;
261 }
262
DisplayFramebufStride()263 u32 DisplayFramebufStride() {
264 return displayFramebuf_ ? displayStride_ : 0;
265 }
DisplayFramebufFormat()266 GEBufferFormat DisplayFramebufFormat() {
267 return displayFramebuf_ ? displayFormat_ : GE_FORMAT_INVALID;
268 }
269
UseBufferedRendering()270 bool UseBufferedRendering() {
271 return useBufferedRendering_;
272 }
273
MayIntersectFramebuffer(u32 start)274 bool MayIntersectFramebuffer(u32 start) {
275 // Clear the cache/kernel bits.
276 start = start & 0x3FFFFFFF;
277 // Most games only have two framebuffers at the start.
278 if (start >= framebufRangeEnd_ || start < PSP_GetVidMemBase()) {
279 return false;
280 }
281 return true;
282 }
283
GetCurrentRenderVFB()284 VirtualFramebuffer *GetCurrentRenderVFB() const {
285 return currentRenderVfb_;
286 }
287 // TODO: Break out into some form of FBO manager
288 VirtualFramebuffer *GetVFBAt(u32 addr);
GetDisplayVFB()289 VirtualFramebuffer *GetDisplayVFB() {
290 return GetVFBAt(displayFramebufPtr_);
291 }
292
GetRenderWidth()293 int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; }
GetRenderHeight()294 int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; }
GetTargetWidth()295 int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; }
GetTargetHeight()296 int GetTargetHeight() const { return currentRenderVfb_ ? currentRenderVfb_->height : 272; }
GetTargetBufferWidth()297 int GetTargetBufferWidth() const { return currentRenderVfb_ ? currentRenderVfb_->bufferWidth : 480; }
GetTargetBufferHeight()298 int GetTargetBufferHeight() const { return currentRenderVfb_ ? currentRenderVfb_->bufferHeight : 272; }
GetTargetStride()299 int GetTargetStride() const { return currentRenderVfb_ ? currentRenderVfb_->fb_stride : 512; }
GetTargetFormat()300 GEBufferFormat GetTargetFormat() const { return currentRenderVfb_ ? currentRenderVfb_->format : displayFormat_; }
301
SetDepthUpdated()302 void SetDepthUpdated() {
303 if (currentRenderVfb_) {
304 currentRenderVfb_->last_frame_depth_render = gpuStats.numFlips;
305 currentRenderVfb_->last_frame_depth_updated = gpuStats.numFlips;
306 }
307 }
SetColorUpdated(int skipDrawReason)308 void SetColorUpdated(int skipDrawReason) {
309 if (currentRenderVfb_) {
310 SetColorUpdated(currentRenderVfb_, skipDrawReason);
311 }
312 }
313 void SetRenderSize(VirtualFramebuffer *vfb);
314 void SetSafeSize(u16 w, u16 h);
315
316 virtual void Resized();
317 virtual void DestroyAllFBOs();
318
319 virtual void DeviceLost();
320 virtual void DeviceRestore(Draw::DrawContext *draw);
321
322 Draw::Framebuffer *GetTempFBO(TempFBO reason, u16 w, u16 h);
323
324 // Debug features
325 virtual bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);
326 virtual bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer);
327 virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer);
328 virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer);
329
Framebuffers()330 const std::vector<VirtualFramebuffer *> &Framebuffers() {
331 return vfbs_;
332 }
333 void ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat);
334
335 protected:
336 virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
337 void SetViewport2D(int x, int y, int w, int h);
338 Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1);
339 virtual void 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) = 0;
340 virtual void Bind2DShader() = 0;
341
342 bool UpdateSize();
343
344 void FlushBeforeCopy();
345 virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra
346
347 // Used by ReadFramebufferToMemory and later framebuffer block copies
348 virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) = 0;
349 void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags);
350
351 void EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height);
352 u32 ColorBufferByteSize(const VirtualFramebuffer *vfb) const;
353
354 void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb);
355 void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged);
356 void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth);
357
358 void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst);
359
360 void ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force = false, bool skipCopy = false);
361 void ShowScreenResolution();
362
363 bool ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const;
364 void DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb);
365 void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp);
366 VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb);
UpdateDownloadTempBuffer(VirtualFramebuffer * nvfb)367 virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {}
368
369 VirtualFramebuffer *CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format);
370
371 void UpdateFramebufUsage(VirtualFramebuffer *vfb);
372
SetColorUpdated(VirtualFramebuffer * dstBuffer,int skipDrawReason)373 static void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) {
374 dstBuffer->memoryUpdated = false;
375 dstBuffer->clutUpdatedBytes = 0;
376 dstBuffer->dirtyAfterDisplay = true;
377 dstBuffer->drawnWidth = dstBuffer->width;
378 dstBuffer->drawnHeight = dstBuffer->height;
379 dstBuffer->drawnFormat = dstBuffer->format;
380 if ((skipDrawReason & SKIPDRAW_SKIPFRAME) == 0)
381 dstBuffer->reallyDirtyAfterDisplay = true;
382 }
383
384 PresentationCommon *presentation_ = nullptr;
385
386 Draw::DrawContext *draw_ = nullptr;
387 TextureCacheCommon *textureCache_ = nullptr;
388 ShaderManagerCommon *shaderManager_ = nullptr;
389 DrawEngineCommon *drawEngine_ = nullptr;
390 bool needBackBufferYSwap_ = false;
391
392 u32 displayFramebufPtr_ = 0;
393 u32 displayStride_ = 0;
394 GEBufferFormat displayFormat_;
395 u32 prevDisplayFramebufPtr_ = 0;
396
397 VirtualFramebuffer *displayFramebuf_ = nullptr;
398 VirtualFramebuffer *prevDisplayFramebuf_ = nullptr;
399 VirtualFramebuffer *prevPrevDisplayFramebuf_ = nullptr;
400 int frameLastFramebufUsed_ = 0;
401
402 VirtualFramebuffer *currentRenderVfb_ = nullptr;
403
404 // The range of PSP memory that may contain FBOs. So we can skip iterating.
405 u32 framebufRangeEnd_ = 0;
406
407 bool useBufferedRendering_ = false;
408 bool postShaderIsUpscalingFilter_ = false;
409 bool postShaderIsSupersampling_ = false;
410
411 std::vector<VirtualFramebuffer *> vfbs_;
412 std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
413
414 bool gameUsesSequentialCopies_ = false;
415
416 // Sampled in BeginFrame/UpdateSize for safety.
417 float renderWidth_ = 0.0f;
418 float renderHeight_ = 0.0f;
419 float renderScaleFactor_ = 1.0f;
420 int pixelWidth_;
421 int pixelHeight_;
422 int bloomHack_ = 0;
423
424 bool needGLESRebinds_ = false;
425 Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM;
426
427 struct TempFBOInfo {
428 Draw::Framebuffer *fbo;
429 int last_frame_used;
430 };
431
432 std::unordered_map<u64, TempFBOInfo> tempFBOs_;
433
434 std::vector<Draw::Framebuffer *> fbosToDelete_;
435
436 // Aggressively delete unused FBOs to save gpu memory.
437 enum {
438 FBO_OLD_AGE = 5,
439 FBO_OLD_USAGE_FLAG = 15,
440 };
441
442 // Thin3D stuff for reinterpreting image data between the various 16-bit formats.
443 // Safe, not optimal - there might be input attachment tricks, etc, but we can't use them
444 // since we don't want N different implementations.
445 Draw::Pipeline *reinterpretFromTo_[3][3]{};
446 Draw::ShaderModule *reinterpretVS_ = nullptr;
447 Draw::SamplerState *reinterpretSampler_ = nullptr;
448 Draw::Buffer *reinterpretVBuf_ = nullptr;
449 };
450