|
| 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 | +#pragma once |
| 19 | + |
| 20 | +#include <cstdint> |
| 21 | + |
| 22 | +// Where the GE stores a depth buffer in VRAM (ppsspp-re geprobe exp8-exp10, docs/ge-precision-and-depth-layout.md). |
| 23 | +// The depth pixel at linear VRAM offset L (zbuf + (y * stride + x) * 2) is stored at Stored(L): with a 32-bit |
| 24 | +// color buffer, address bits 5 to log2(T) - 1 rotate left by one (bits 9 and 10 swap at T 0), then |
| 25 | +// (T << 3) | 0x40 is XORed in (0x600 at T 0). T is sceGeEdramSetAddrTranslation's value: 0, 0x200, 0x400, |
| 26 | +// 0x800 or 0x1000. The offsets are absolute, independent of the buffer's address and stride. |
| 27 | +// |
| 28 | +// Bits 0-4 never change, so each 32-byte aligned run of 16 pixels is stored together. The CPU (and texturing) |
| 29 | +// sees the same mapping through VRAM's mirrors: an access at 0x04200000 + L goes to Stored(L) of the 16-bit |
| 30 | +// layout, at 0x04600000 + L to the 32-bit one's (exp88). |
| 31 | +struct DepthLayout { |
| 32 | + uint32_t rotMask = 0; |
| 33 | + int rotShift = 0; |
| 34 | + uint32_t xorBits = 0; |
| 35 | + |
| 36 | + constexpr uint32_t Stored(uint32_t offset) const { |
| 37 | + const uint32_t f = offset & rotMask; |
| 38 | + return ((offset & ~rotMask) | (((f << 1) | (f >> rotShift)) & rotMask)) ^ xorBits; |
| 39 | + } |
| 40 | +}; |
| 41 | + |
| 42 | +constexpr DepthLayout GetDepthLayout(uint32_t translation, bool color32) { |
| 43 | + DepthLayout layout; |
| 44 | + if (translation == 0) { |
| 45 | + layout.xorBits = 0x600; |
| 46 | + if (color32) { |
| 47 | + layout.rotMask = 0x600; |
| 48 | + layout.rotShift = 1; |
| 49 | + } |
| 50 | + return layout; |
| 51 | + } |
| 52 | + layout.xorBits = (translation << 3) | 0x40; |
| 53 | + int top = 0; |
| 54 | + while ((2u << top) <= translation) |
| 55 | + top++; |
| 56 | + // Bits 5 to top - 1. |
| 57 | + if (color32 && top - 5 > 1) { |
| 58 | + layout.rotMask = ((1u << (top - 5)) - 1) << 5; |
| 59 | + layout.rotShift = top - 5 - 1; |
| 60 | + } |
| 61 | + return layout; |
| 62 | +} |
| 63 | + |
| 64 | +// The translations as an index 0 to 4: 0, 0x200, 0x400, 0x800, 0x1000. |
| 65 | +constexpr int DepthTranslationIndex(uint32_t translation) { |
| 66 | + int index = 0; |
| 67 | + while (translation >= 0x200 && index < 4) { |
| 68 | + translation >>= 1; |
| 69 | + index++; |
| 70 | + } |
| 71 | + return index; |
| 72 | +} |
| 73 | + |
| 74 | +constexpr uint32_t DepthTranslationFromIndex(int index) { |
| 75 | + return index == 0 ? 0 : 0x100 << index; |
| 76 | +} |
| 77 | + |
| 78 | +// Every layout there is, by [color32][translation index]. |
| 79 | +inline constexpr DepthLayout DEPTH_LAYOUTS[2][5] = { |
| 80 | + { GetDepthLayout(0, false), GetDepthLayout(0x200, false), GetDepthLayout(0x400, false), GetDepthLayout(0x800, false), GetDepthLayout(0x1000, false) }, |
| 81 | + { GetDepthLayout(0, true), GetDepthLayout(0x200, true), GetDepthLayout(0x400, true), GetDepthLayout(0x800, true), GetDepthLayout(0x1000, true) }, |
| 82 | +}; |
| 83 | + |
| 84 | +// A couple of exp8-exp10's measurements (TestDepthSwizzle has more). |
| 85 | +static_assert(DEPTH_LAYOUTS[0][2].Stored(0x088000) == 0x08a040, "16-bit layout at the default translation"); |
| 86 | +static_assert(DEPTH_LAYOUTS[1][0].Stored(0x03171e) == 0x03111e, "32-bit layout at translation 0"); |
0 commit comments