@@ -85,13 +85,94 @@ const UniformBufferDesc depthUBDesc{ sizeof(DepthUB), {
85
85
{ " u_depthTo8" , -1 , -1 , UniformType::FLOAT4, 32 },
86
86
} };
87
87
88
+ static const char *stencil_dl_fs = R"(
89
+ #ifdef GL_ES
90
+ #ifdef GL_FRAGMENT_PRECISION_HIGH
91
+ precision highp float;
92
+ #else
93
+ precision mediump float;
94
+ #endif
95
+ #endif
96
+ #if __VERSION__ >= 130
97
+ #define varying in
98
+ #define texture2D texture
99
+ #define gl_FragColor fragColor0
100
+ out vec4 fragColor0;
101
+ #endif
102
+ varying vec2 v_texcoord;
103
+ lowp uniform usampler2D tex;
104
+ void main() {
105
+ uint stencil = texture2D(tex, v_texcoord).r;
106
+ float scaled = float(stencil) / 255.0;
107
+ gl_FragColor = vec4(scaled, scaled, scaled, scaled);
108
+ }
109
+ )" ;
110
+
111
+ static const char *stencil_vs = R"(
112
+ #ifdef GL_ES
113
+ precision highp float;
114
+ #endif
115
+ #if __VERSION__ >= 130
116
+ #define attribute in
117
+ #define varying out
118
+ #endif
119
+ attribute vec2 a_position;
120
+ varying vec2 v_texcoord;
121
+ void main() {
122
+ v_texcoord = a_position * 2.0;
123
+ gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);
124
+ }
125
+ )" ;
126
+
88
127
static bool SupportsDepthTexturing () {
89
128
if (gl_extensions.IsGLES ) {
90
129
return gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3 );
91
130
}
92
131
return gl_extensions.VersionGEThan (3 , 0 );
93
132
}
94
133
134
+ static Draw::Pipeline *CreateReadbackPipeline (Draw::DrawContext *draw, const char *tag, const UniformBufferDesc *ubDesc, const char *fs, const char *fsTag, const char *vs, const char *vsTag) {
135
+ using namespace Draw ;
136
+
137
+ const ShaderLanguageDesc &shaderLanguageDesc = draw->GetShaderLanguageDesc ();
138
+
139
+ ShaderModule *readbackFs = draw->CreateShaderModule (ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage , (const uint8_t *)fs, strlen (fs), fsTag);
140
+ ShaderModule *readbackVs = draw->CreateShaderModule (ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage , (const uint8_t *)vs, strlen (vs), vsTag);
141
+ _assert_ (readbackFs && readbackVs);
142
+
143
+ InputLayoutDesc desc = {
144
+ {
145
+ { 8 , false },
146
+ },
147
+ {
148
+ { 0 , SEM_POSITION, DataFormat::R32G32_FLOAT, 0 },
149
+ },
150
+ };
151
+ InputLayout *inputLayout = draw->CreateInputLayout (desc);
152
+
153
+ BlendState *blendOff = draw->CreateBlendState ({ false , 0xF });
154
+ DepthStencilState *stencilIgnore = draw->CreateDepthStencilState ({});
155
+ RasterState *rasterNoCull = draw->CreateRasterState ({});
156
+
157
+ PipelineDesc readbackDesc{
158
+ Primitive::TRIANGLE_LIST,
159
+ { readbackVs, readbackFs },
160
+ inputLayout, stencilIgnore, blendOff, rasterNoCull, ubDesc,
161
+ };
162
+ Draw::Pipeline *pipeline = draw->CreateGraphicsPipeline (readbackDesc, tag);
163
+ _assert_ (pipeline);
164
+
165
+ rasterNoCull->Release ();
166
+ blendOff->Release ();
167
+ stencilIgnore->Release ();
168
+ inputLayout->Release ();
169
+
170
+ readbackFs->Release ();
171
+ readbackVs->Release ();
172
+
173
+ return pipeline;
174
+ }
175
+
95
176
bool FramebufferManagerGLES::ReadbackDepthbufferSync (Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) {
96
177
using namespace Draw ;
97
178
@@ -117,44 +198,8 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int
117
198
118
199
if (useColorPath) {
119
200
if (!depthReadbackPipeline_) {
120
- const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc ();
121
-
122
- ShaderModule *depthReadbackFs = draw_->CreateShaderModule (ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage , (const uint8_t *)depth_dl_fs, strlen (depth_dl_fs), " depth_dl_fs" );
123
- ShaderModule *depthReadbackVs = draw_->CreateShaderModule (ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage , (const uint8_t *)depth_vs, strlen (depth_vs), " depth_vs" );
124
- _assert_ (depthReadbackFs && depthReadbackVs);
125
-
126
- InputLayoutDesc desc = {
127
- {
128
- { 8 , false },
129
- },
130
- {
131
- { 0 , SEM_POSITION, DataFormat::R32G32_FLOAT, 0 },
132
- },
133
- };
134
- InputLayout *inputLayout = draw_->CreateInputLayout (desc);
135
-
136
- BlendState *blendOff = draw_->CreateBlendState ({ false , 0xF });
137
- DepthStencilState *stencilIgnore = draw_->CreateDepthStencilState ({});
138
- RasterState *rasterNoCull = draw_->CreateRasterState ({});
139
-
140
- PipelineDesc depthReadbackDesc{
141
- Primitive::TRIANGLE_LIST,
142
- { depthReadbackVs, depthReadbackFs },
143
- inputLayout, stencilIgnore, blendOff, rasterNoCull, &depthUBDesc,
144
- };
145
- depthReadbackPipeline_ = draw_->CreateGraphicsPipeline (depthReadbackDesc, " depth_dl" );
146
- _assert_ (depthReadbackPipeline_);
147
-
148
- rasterNoCull->Release ();
149
- blendOff->Release ();
150
- stencilIgnore->Release ();
151
- inputLayout->Release ();
152
-
153
- depthReadbackFs->Release ();
154
- depthReadbackVs->Release ();
155
-
156
- SamplerStateDesc descNearest{};
157
- depthReadbackSampler_ = draw_->CreateSamplerState (descNearest);
201
+ depthReadbackPipeline_ = CreateReadbackPipeline (draw_, " depth_dl" , &depthUBDesc, depth_dl_fs, " depth_dl_fs" , depth_vs, " depth_vs" );
202
+ depthReadbackSampler_ = draw_->CreateSamplerState ({});
158
203
}
159
204
160
205
shaderManager_->DirtyLastShader ();
@@ -242,3 +287,75 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int
242
287
gstate_c.Dirty (DIRTY_ALL_RENDER_STATE);
243
288
return true ;
244
289
}
290
+
291
+ // Well, this is not depth, but it's depth/stencil related.
292
+ bool FramebufferManagerGLES::ReadbackStencilbufferSync (Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride) {
293
+ using namespace Draw ;
294
+
295
+ if (!fbo) {
296
+ ERROR_LOG_REPORT_ONCE (vfbfbozero, SCEGE, " ReadbackStencilbufferSync: bad fbo" );
297
+ return false ;
298
+ }
299
+
300
+ const bool useColorPath = gl_extensions.IsGLES ;
301
+ if (!useColorPath) {
302
+ return draw_->CopyFramebufferToMemorySync (fbo, FB_STENCIL_BIT, x, y, w, h, DataFormat::S8, pixels, pixelsStride, " ReadbackStencilbufferSync" );
303
+ }
304
+
305
+ // Unsupported below GLES 3.1 or without ARB_stencil_texturing.
306
+ // OES_texture_stencil8 is related, but used to specify texture data.
307
+ if ((gl_extensions.IsGLES && !gl_extensions.VersionGEThan (3 , 1 )) && !gl_extensions.ARB_stencil_texturing )
308
+ return false ;
309
+
310
+ // Pixel size always 4 here because we always request RGBA back.
311
+ const u32 bufSize = w * h * 4 ;
312
+ if (!convBuf_ || convBufSize_ < bufSize) {
313
+ delete[] convBuf_;
314
+ convBuf_ = new u8[bufSize];
315
+ convBufSize_ = bufSize;
316
+ }
317
+
318
+ if (!stencilReadbackPipeline_) {
319
+ stencilReadbackPipeline_ = CreateReadbackPipeline (draw_, " stencil_dl" , &depthUBDesc, stencil_dl_fs, " stencil_dl_fs" , stencil_vs, " stencil_vs" );
320
+ stencilReadbackSampler_ = draw_->CreateSamplerState ({});
321
+ }
322
+
323
+ shaderManager_->DirtyLastShader ();
324
+ auto *blitFBO = GetTempFBO (TempFBO::COPY, fbo->Width (), fbo->Height ());
325
+ draw_->BindFramebufferAsRenderTarget (blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, " ReadbackStencilbufferSync" );
326
+ Draw::Viewport viewport = { 0 .0f , 0 .0f , (float )fbo->Width (), (float )fbo->Height (), 0 .0f , 1 .0f };
327
+ draw_->SetViewports (1 , &viewport);
328
+
329
+ draw_->BindFramebufferAsTexture (fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT, 0 );
330
+ draw_->BindSamplerStates (TEX_SLOT_PSP_TEXTURE, 1 , &stencilReadbackSampler_);
331
+
332
+ // We must bind the program after starting the render pass.
333
+ draw_->SetScissorRect (0 , 0 , w, h);
334
+ draw_->BindPipeline (stencilReadbackPipeline_);
335
+
336
+ // Fullscreen triangle coordinates.
337
+ static const float positions[6 ] = {
338
+ 0.0 , 0.0 ,
339
+ 1.0 , 0.0 ,
340
+ 0.0 , 1.0 ,
341
+ };
342
+ draw_->DrawUP (positions, 3 );
343
+
344
+ draw_->CopyFramebufferToMemorySync (blitFBO, FB_COLOR_BIT, x, y, w, h, DataFormat::R8G8B8A8_UNORM, convBuf_, w, " ReadbackStencilbufferSync" );
345
+
346
+ textureCache_->ForgetLastTexture ();
347
+
348
+ // TODO: Use 1/4 width to write all values directly and skip CPU conversion?
349
+ uint8_t *dest = pixels;
350
+ const u32_le *packed32 = (u32_le *)convBuf_;
351
+ for (int yp = 0 ; yp < h; ++yp) {
352
+ for (int xp = 0 ; xp < w; ++xp) {
353
+ dest[xp] = packed32[xp] & 0xFF ;
354
+ }
355
+ dest += pixelsStride;
356
+ packed32 += w;
357
+ }
358
+
359
+ gstate_c.Dirty (DIRTY_ALL_RENDER_STATE);
360
+ return true ;
361
+ }
0 commit comments