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 &params, 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