CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/Common/DepthBufferCommon.cpp
Views: 1401
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
#include <algorithm>
19
20
#include "Common/GPU/OpenGL/GLFeatures.h"
21
#include "Common/LogReporting.h"
22
#include "Core/ConfigValues.h"
23
#include "GPU/Common/GPUStateUtils.h"
24
#include "GPU/Common/DrawEngineCommon.h"
25
#include "GPU/Common/FramebufferManagerCommon.h"
26
#include "GPU/Common/TextureCacheCommon.h"
27
#include "Common/GPU/ShaderWriter.h"
28
29
30
static const InputDef vs_inputs[] = {
31
{ "vec2", "a_position", Draw::SEM_POSITION },
32
};
33
34
struct DepthUB {
35
float u_depthFactor[4];
36
float u_depthShift[4];
37
float u_depthTo8[4];
38
};
39
40
const UniformDef depthUniforms[] = {
41
{ "vec4", "u_depthFactor", 0 },
42
{ "vec4", "u_depthShift", 1},
43
{ "vec4", "u_depthTo8", 2},
44
};
45
46
const UniformBufferDesc depthUBDesc{ sizeof(DepthUB), {
47
{ "u_depthFactor", -1, -1, UniformType::FLOAT4, 0 },
48
{ "u_depthShift", -1, -1, UniformType::FLOAT4, 16 },
49
{ "u_depthTo8", -1, -1, UniformType::FLOAT4, 32 },
50
} };
51
52
static const SamplerDef samplers[] = {
53
{ 0, "tex" },
54
};
55
56
static const VaryingDef varyings[] = {
57
{ "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" },
58
};
59
60
void GenerateDepthDownloadFs(ShaderWriter &writer) {
61
writer.DeclareSamplers(samplers);
62
writer.BeginFSMain(depthUniforms, varyings);
63
writer.C(" float depth = ").SampleTexture2D("tex", "v_texcoord").C(".r; \n");
64
// At this point, clamped maps [0, 1] to [0, 65535].
65
writer.C(" float clamped = clamp((depth - u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0);\n");
66
writer.C(" vec4 enc = u_depthShift * clamped;\n");
67
writer.C(" enc = floor(mod(enc, 256.0)) * u_depthTo8;\n");
68
writer.C(" vec4 outColor = enc.yzww;\n"); // Let's ignore the bits outside 16 bit precision.
69
writer.EndFSMain("outColor");
70
}
71
72
void GenerateDepthDownloadVs(ShaderWriter &writer) {
73
writer.BeginVSMain(vs_inputs, Slice<UniformDef>::empty(), varyings);
74
writer.C("v_texcoord = a_position * 2.0;\n");
75
writer.C("gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);");
76
writer.EndVSMain(varyings);
77
}
78
79
static const char * const stencil_dl_fs = R"(
80
#ifdef GL_ES
81
#ifdef GL_FRAGMENT_PRECISION_HIGH
82
precision highp float;
83
#else
84
precision mediump float;
85
#endif
86
#endif
87
#if __VERSION__ >= 130
88
#define varying in
89
#define texture2D texture
90
#define gl_FragColor fragColor0
91
out vec4 fragColor0;
92
#endif
93
varying vec2 v_texcoord;
94
lowp uniform usampler2D tex;
95
void main() {
96
uint stencil = texture2D(tex, v_texcoord).r;
97
float scaled = float(stencil) / 255.0;
98
gl_FragColor = vec4(scaled, scaled, scaled, scaled);
99
}
100
)";
101
102
static const char * const stencil_vs = R"(
103
#ifdef GL_ES
104
precision highp float;
105
#endif
106
#if __VERSION__ >= 130
107
#define attribute in
108
#define varying out
109
#endif
110
attribute vec2 a_position;
111
varying vec2 v_texcoord;
112
void main() {
113
v_texcoord = a_position * 2.0;
114
gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);
115
}
116
)";
117
118
static bool SupportsDepthTexturing() {
119
if (gl_extensions.IsGLES) {
120
return gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3);
121
}
122
return gl_extensions.ARB_texture_float;
123
}
124
125
Draw::Pipeline *CreateReadbackPipeline(Draw::DrawContext *draw, const char *tag, const UniformBufferDesc *ubDesc, const char *fs, const char *fsTag, const char *vs, const char *vsTag) {
126
using namespace Draw;
127
128
const ShaderLanguageDesc &shaderLanguageDesc = draw->GetShaderLanguageDesc();
129
130
ShaderModule *readbackFs = draw->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fs, strlen(fs), fsTag);
131
ShaderModule *readbackVs = draw->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vs, strlen(vs), vsTag);
132
_assert_(readbackFs && readbackVs);
133
134
static const InputLayoutDesc desc = {
135
8,
136
{
137
{ SEM_POSITION, DataFormat::R32G32_FLOAT, 0 },
138
},
139
};
140
InputLayout *inputLayout = draw->CreateInputLayout(desc);
141
142
BlendState *blendOff = draw->CreateBlendState({ false, 0xF });
143
DepthStencilState *stencilIgnore = draw->CreateDepthStencilState({});
144
RasterState *rasterNoCull = draw->CreateRasterState({});
145
146
PipelineDesc readbackDesc{
147
Primitive::TRIANGLE_LIST,
148
{ readbackVs, readbackFs },
149
inputLayout, stencilIgnore, blendOff, rasterNoCull, ubDesc,
150
};
151
Draw::Pipeline *pipeline = draw->CreateGraphicsPipeline(readbackDesc, tag);
152
_assert_(pipeline);
153
154
rasterNoCull->Release();
155
blendOff->Release();
156
stencilIgnore->Release();
157
inputLayout->Release();
158
159
readbackFs->Release();
160
readbackVs->Release();
161
162
return pipeline;
163
}
164
165
bool FramebufferManagerCommon::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode) {
166
using namespace Draw;
167
168
if (!fbo) {
169
ERROR_LOG_REPORT_ONCE(vfbfbozero, Log::sceGe, "ReadbackDepthbufferSync: bad fbo");
170
return false;
171
}
172
// Old desktop GL can download depth, but not upload.
173
if (gl_extensions.IsGLES && !SupportsDepthTexturing()) {
174
return false;
175
}
176
177
// Pixel size always 4 here because we always request float or RGBA.
178
const u32 bufSize = destW * destH * 4;
179
if (!convBuf_ || convBufSize_ < bufSize) {
180
delete[] convBuf_;
181
convBuf_ = new u8[bufSize];
182
convBufSize_ = bufSize;
183
}
184
185
float scaleX = (float)destW / w;
186
float scaleY = (float)destH / h;
187
188
bool useColorPath = gl_extensions.IsGLES || scaleX != 1.0f || scaleY != 1.0f;
189
bool format16Bit = false;
190
191
if (useColorPath) {
192
if (!depthReadbackPipeline_) {
193
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
194
char depth_dl_fs[1024];
195
char depth_dl_vs[1024];
196
ShaderWriter fsWriter(depth_dl_fs, shaderLanguageDesc, ShaderStage::Fragment);
197
ShaderWriter vsWriter(depth_dl_vs, shaderLanguageDesc, ShaderStage::Vertex);
198
GenerateDepthDownloadFs(fsWriter);
199
GenerateDepthDownloadVs(vsWriter);
200
depthReadbackPipeline_ = CreateReadbackPipeline(draw_, "depth_dl", &depthUBDesc, depth_dl_fs, "depth_dl_fs", depth_dl_vs, "depth_dl_vs");
201
depthReadbackSampler_ = draw_->CreateSamplerState({});
202
}
203
204
shaderManager_->DirtyLastShader();
205
auto *blitFBO = GetTempFBO(TempFBO::Z_COPY, fbo->Width() * scaleX, fbo->Height() * scaleY);
206
draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync");
207
Draw::Viewport viewport = { 0.0f, 0.0f, (float)destW, (float)destH, 0.0f, 1.0f };
208
draw_->SetViewport(viewport);
209
draw_->SetScissorRect(0, 0, fbo->Width() * scaleX, fbo->Height() * scaleY);
210
211
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0);
212
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &depthReadbackSampler_);
213
214
// We must bind the program after starting the render pass.
215
draw_->BindPipeline(depthReadbackPipeline_);
216
217
DepthUB ub{};
218
219
// Setting this to 0.95f eliminates flickering lights with delayed readback in Syphon Filter.
220
// That's pretty ugly though! But we'll need to do that if we're gonna enable delayed readback in those games.
221
const float fudgeFactor = 1.0f;
222
DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags());
223
ub.u_depthFactor[0] = depthScale.Offset();
224
ub.u_depthFactor[1] = depthScale.Scale();
225
226
// These are for packing a float in u8x4 colors. We should support more suitable readback formats on APIs that can do it.
227
static constexpr float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f };
228
memcpy(ub.u_depthShift, shifts, sizeof(shifts));
229
static constexpr float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f };
230
memcpy(ub.u_depthTo8, to8, sizeof(to8));
231
232
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
233
234
// Fullscreen triangle coordinates.
235
static const float positions[6] = {
236
0.0, 0.0,
237
1.0, 0.0,
238
0.0, 1.0,
239
};
240
draw_->DrawUP(positions, 3);
241
242
draw_->CopyFramebufferToMemory(blitFBO, FB_COLOR_BIT,
243
x * scaleX, y * scaleY, w * scaleX, h * scaleY,
244
DataFormat::R8G8B8A8_UNORM, convBuf_, destW, mode, "ReadbackDepthbufferSync");
245
246
textureCache_->ForgetLastTexture();
247
// TODO: Use 4444 (or better, R16_UNORM) so we can copy lines directly (instead of 32 -> 16 on CPU)?
248
format16Bit = true;
249
} else {
250
draw_->CopyFramebufferToMemory(fbo, FB_DEPTH_BIT, x, y, w, h, DataFormat::D32F, convBuf_, w, mode, "ReadbackDepthbufferSync");
251
format16Bit = false;
252
}
253
254
// TODO: Move this conversion into the backends.
255
if (format16Bit) {
256
// In this case, we used the shader to apply depth scale factors.
257
// This can be SSE'd or NEON'd very efficiently, though ideally we would avoid this conversion by using R16_UNORM for readback.
258
uint16_t *dest = pixels;
259
const u32_le *packed32 = (u32_le *)convBuf_;
260
for (int yp = 0; yp < destH; ++yp) {
261
for (int xp = 0; xp < destW; ++xp) {
262
dest[xp] = packed32[xp] & 0xFFFF;
263
}
264
dest += pixelsStride;
265
packed32 += destW;
266
}
267
} else {
268
// TODO: Apply this in the shader? May have precision issues if it becomes important to match.
269
// We downloaded float values directly in this case.
270
uint16_t *dest = pixels;
271
const float *packedf = (float *)convBuf_;
272
DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags());
273
for (int yp = 0; yp < destH; ++yp) {
274
for (int xp = 0; xp < destW; ++xp) {
275
float scaled = depthScale.DecodeToU16(packedf[xp]);
276
if (scaled <= 0.0f) {
277
dest[xp] = 0;
278
} else if (scaled >= 65535.0f) {
279
dest[xp] = 65535;
280
} else {
281
dest[xp] = (int)scaled;
282
}
283
}
284
dest += pixelsStride;
285
packedf += destW;
286
}
287
}
288
289
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
290
return true;
291
}
292
293