mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-06 04:35:29 +02:00
Merge pull request #16195 from unknownbrackets/gles-depth-cleanup
GLES: Use Draw for depth readback shader
This commit is contained in:
@@ -386,6 +386,7 @@ void CheckGLExtensions() {
|
||||
gl_extensions.OES_texture_3D = g_set_gl_extensions.count("GL_OES_texture_3D") != 0;
|
||||
gl_extensions.EXT_buffer_storage = g_set_gl_extensions.count("GL_EXT_buffer_storage") != 0;
|
||||
gl_extensions.EXT_clip_cull_distance = g_set_gl_extensions.count("GL_EXT_clip_cull_distance") != 0;
|
||||
gl_extensions.EXT_depth_clamp = g_set_gl_extensions.count("GL_EXT_depth_clamp") != 0;
|
||||
gl_extensions.APPLE_clip_distance = g_set_gl_extensions.count("GL_APPLE_clip_distance") != 0;
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
@@ -87,6 +87,7 @@ struct GLExtensions {
|
||||
bool EXT_draw_instanced;
|
||||
bool EXT_buffer_storage;
|
||||
bool EXT_clip_cull_distance;
|
||||
bool EXT_depth_clamp;
|
||||
|
||||
// NV
|
||||
bool NV_copy_image;
|
||||
|
||||
@@ -551,7 +551,7 @@ OpenGLContext::OpenGLContext() {
|
||||
caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3;
|
||||
caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported;
|
||||
caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported;
|
||||
caps_.depthClampSupported = gl_extensions.ARB_depth_clamp;
|
||||
caps_.depthClampSupported = gl_extensions.ARB_depth_clamp || gl_extensions.EXT_depth_clamp;
|
||||
caps_.blendMinMaxSupported = gl_extensions.EXT_blend_minmax;
|
||||
|
||||
if (gl_extensions.IsGLES) {
|
||||
|
||||
@@ -2538,6 +2538,12 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32
|
||||
}
|
||||
// No need to free on failure, that's the caller's job (it likely will reuse a buffer.)
|
||||
bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w, "GetDepthBuffer");
|
||||
if (!retval) {
|
||||
// Try ReadbackDepthbufferSync, in case GLES.
|
||||
buffer.Allocate(w, h, GPU_DBG_FORMAT_16BIT, flipY);
|
||||
retval = ReadbackDepthbufferSync(vfb->fbo, 0, 0, w, h, (uint16_t *)buffer.GetData(), w);
|
||||
}
|
||||
|
||||
// After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe.
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
// That may have unbound the framebuffer, rebind to avoid crashes when debugging.
|
||||
@@ -2604,7 +2610,7 @@ void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb,
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 fb_address = vfb->fb_address;
|
||||
const u32 fb_address = channel == RASTER_COLOR ? vfb->fb_address : vfb->z_address;
|
||||
|
||||
Draw::DataFormat destFormat = channel == RASTER_COLOR ? GEFormatToThin3D(vfb->fb_format) : GEFormatToThin3D(GE_FORMAT_DEPTH16);
|
||||
const int dstBpp = (int)DataFormatSizeInBytes(destFormat);
|
||||
@@ -2627,31 +2633,23 @@ void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb,
|
||||
// Right now that's always 8888.
|
||||
DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr);
|
||||
|
||||
if (destPtr) {
|
||||
if (channel == RASTER_DEPTH)
|
||||
ReadbackDepthbufferSync(vfb, x, y, w, h);
|
||||
else
|
||||
draw_->CopyFramebufferToMemorySync(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride, "ReadbackFramebufferSync");
|
||||
|
||||
char tag[128];
|
||||
size_t len = snprintf(tag, sizeof(tag), "FramebufferPack/%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, w, h, GeBufferFormatToString(vfb->fb_format));
|
||||
NotifyMemInfo(MemBlockFlags::WRITE, fb_address + dstByteOffset, dstSize, tag, len);
|
||||
if (channel == RASTER_DEPTH) {
|
||||
_assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid");
|
||||
ReadbackDepthbufferSync(vfb->fbo, x, y, w, h, (uint16_t *)destPtr, stride);
|
||||
} else {
|
||||
ERROR_LOG(G3D, "ReadbackFramebufferSync: Tried to readback to bad address %08x (stride = %d)", fb_address + dstByteOffset, vfb->fb_stride);
|
||||
draw_->CopyFramebufferToMemorySync(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, stride, "ReadbackFramebufferSync");
|
||||
}
|
||||
|
||||
char tag[128];
|
||||
size_t len = snprintf(tag, sizeof(tag), "FramebufferPack/%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, w, h, GeBufferFormatToString(vfb->fb_format));
|
||||
NotifyMemInfo(MemBlockFlags::WRITE, fb_address + dstByteOffset, dstSize, tag, len);
|
||||
|
||||
gpuStats.numReadbacks++;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
|
||||
_assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid");
|
||||
|
||||
bool FramebufferManagerCommon::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) {
|
||||
Draw::DataFormat destFormat = GEFormatToThin3D(GE_FORMAT_DEPTH16);
|
||||
const int dstByteOffset = (y * vfb->z_stride + x) * 2;
|
||||
u8 *destPtr = Memory::GetPointerWriteUnchecked(vfb->z_address + dstByteOffset);
|
||||
if (!draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->z_stride, "ReadbackDepthbufferSync")) {
|
||||
WARN_LOG(G3D, "ReadbackDepthbufferSync failed");
|
||||
}
|
||||
return draw_->CopyFramebufferToMemorySync(fbo, Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, pixels, pixelsStride, "ReadbackDepthbufferSync");
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) {
|
||||
@@ -2811,6 +2809,8 @@ void FramebufferManagerCommon::DeviceLost() {
|
||||
}
|
||||
DoRelease(stencilUploadSampler_);
|
||||
DoRelease(stencilUploadPipeline_);
|
||||
DoRelease(depthReadbackSampler_);
|
||||
DoRelease(depthReadbackPipeline_);
|
||||
DoRelease(draw2DPipelineColor_);
|
||||
DoRelease(draw2DPipelineColorRect2Lin_);
|
||||
DoRelease(draw2DPipelineDepth_);
|
||||
|
||||
@@ -443,7 +443,7 @@ public:
|
||||
protected:
|
||||
virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel);
|
||||
// Used for when a shader is required, such as GLES.
|
||||
virtual void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
virtual bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride);
|
||||
void SetViewport2D(int x, int y, int w, int h);
|
||||
Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
|
||||
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);
|
||||
@@ -571,6 +571,9 @@ protected:
|
||||
Draw::Pipeline *stencilUploadPipeline_ = nullptr;
|
||||
Draw::SamplerState *stencilUploadSampler_ = nullptr;
|
||||
|
||||
Draw::Pipeline *depthReadbackPipeline_ = nullptr;
|
||||
Draw::SamplerState *depthReadbackSampler_ = nullptr;
|
||||
|
||||
// Draw2D pipelines
|
||||
Draw2DPipeline *draw2DPipelineColor_ = nullptr;
|
||||
Draw2DPipeline *draw2DPipelineColorRect2Lin_ = nullptr;
|
||||
|
||||
@@ -49,11 +49,11 @@ public:
|
||||
|
||||
protected:
|
||||
void DecimateFBOs() override;
|
||||
void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;
|
||||
void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) override;
|
||||
|
||||
private:
|
||||
bool GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer);
|
||||
void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
|
||||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9 deviceEx_;
|
||||
|
||||
+130
-91
@@ -40,19 +40,18 @@ precision mediump float;
|
||||
#define gl_FragColor fragColor0
|
||||
out vec4 fragColor0;
|
||||
#endif
|
||||
varying vec2 v_texcoord0;
|
||||
uniform vec2 u_depthFactor;
|
||||
varying vec2 v_texcoord;
|
||||
uniform vec4 u_depthFactor;
|
||||
uniform vec4 u_depthShift;
|
||||
uniform vec4 u_depthTo8;
|
||||
uniform sampler2D tex;
|
||||
void main() {
|
||||
float depth = texture2D(tex, v_texcoord0).r;
|
||||
float depth = texture2D(tex, v_texcoord).r;
|
||||
// At this point, clamped maps [0, 1] to [0, 65535].
|
||||
float clamped = clamp((depth + u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0);
|
||||
|
||||
vec4 enc = u_depthShift * clamped;
|
||||
enc = floor(mod(enc, 256.0)) * u_depthTo8;
|
||||
enc = enc * u_depthTo8;
|
||||
// Let's ignore the bits outside 16 bit precision.
|
||||
gl_FragColor = enc.yzww;
|
||||
}
|
||||
@@ -66,140 +65,180 @@ precision highp float;
|
||||
#define attribute in
|
||||
#define varying out
|
||||
#endif
|
||||
attribute vec4 a_position;
|
||||
attribute vec2 a_texcoord0;
|
||||
varying vec2 v_texcoord0;
|
||||
attribute vec2 a_position;
|
||||
varying vec2 v_texcoord;
|
||||
void main() {
|
||||
v_texcoord0 = a_texcoord0;
|
||||
gl_Position = a_position;
|
||||
v_texcoord = a_position * 2.0;
|
||||
gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
|
||||
if (!vfb->fbo) {
|
||||
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: vfb->fbo == 0");
|
||||
return;
|
||||
struct DepthUB {
|
||||
float u_depthFactor[4];
|
||||
float u_depthShift[4];
|
||||
float u_depthTo8[4];
|
||||
};
|
||||
|
||||
const UniformBufferDesc depthUBDesc{ sizeof(DepthUB), {
|
||||
{ "u_depthFactor", -1, -1, UniformType::FLOAT4, 0 },
|
||||
{ "u_depthShift", -1, -1, UniformType::FLOAT4, 16 },
|
||||
{ "u_depthTo8", -1, -1, UniformType::FLOAT4, 32 },
|
||||
} };
|
||||
|
||||
static bool SupportsDepthTexturing() {
|
||||
if (gl_extensions.IsGLES) {
|
||||
return gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3);
|
||||
}
|
||||
return gl_extensions.VersionGEThan(3, 0);
|
||||
}
|
||||
|
||||
bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) {
|
||||
using namespace Draw;
|
||||
|
||||
if (!fbo) {
|
||||
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: bad fbo");
|
||||
return false;
|
||||
}
|
||||
// Old desktop GL can download depth, but not upload.
|
||||
if (gl_extensions.IsGLES && !SupportsDepthTexturing()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pixel size always 4 here because we always request float
|
||||
const u32 bufSize = vfb->z_stride * (h - y) * 4;
|
||||
const u32 z_address = vfb->z_address;
|
||||
const int packWidth = std::min((int)vfb->z_stride, std::min(x + w, (int)vfb->width));
|
||||
|
||||
// Pixel size always 4 here because we always request float or RGBA.
|
||||
const u32 bufSize = w * h * 4;
|
||||
if (!convBuf_ || convBufSize_ < bufSize) {
|
||||
delete[] convBuf_;
|
||||
convBuf_ = new u8[bufSize];
|
||||
convBufSize_ = bufSize;
|
||||
}
|
||||
|
||||
DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address);
|
||||
|
||||
const bool useColorPath = gl_extensions.IsGLES;
|
||||
bool format16Bit = false;
|
||||
|
||||
GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
if (useColorPath) {
|
||||
if (!depthDownloadProgram_) {
|
||||
std::string errorString;
|
||||
static std::string vs_code, fs_code;
|
||||
vs_code = ApplyGLSLPrelude(depth_vs, GL_VERTEX_SHADER);
|
||||
fs_code = ApplyGLSLPrelude(depth_dl_fs, GL_FRAGMENT_SHADER);
|
||||
std::vector<GLRShader *> shaders;
|
||||
shaders.push_back(render->CreateShader(GL_VERTEX_SHADER, vs_code, "depth_dl"));
|
||||
shaders.push_back(render->CreateShader(GL_FRAGMENT_SHADER, fs_code, "depth_dl"));
|
||||
std::vector<GLRProgram::Semantic> semantics;
|
||||
semantics.push_back({ 0, "a_position" });
|
||||
semantics.push_back({ 1, "a_texcoord0" });
|
||||
std::vector<GLRProgram::UniformLocQuery> queries;
|
||||
queries.push_back({ &u_depthDownloadTex, "tex" });
|
||||
queries.push_back({ &u_depthDownloadFactor, "u_depthFactor" });
|
||||
queries.push_back({ &u_depthDownloadShift, "u_depthShift" });
|
||||
queries.push_back({ &u_depthDownloadTo8, "u_depthTo8" });
|
||||
std::vector<GLRProgram::Initializer> inits;
|
||||
inits.push_back({ &u_depthDownloadTex, 0, TEX_SLOT_PSP_TEXTURE });
|
||||
GLRProgramFlags flags{};
|
||||
depthDownloadProgram_ = render->CreateProgram(shaders, semantics, queries, inits, flags);
|
||||
for (auto iter : shaders) {
|
||||
render->DeleteShader(iter);
|
||||
}
|
||||
if (!depthDownloadProgram_) {
|
||||
ERROR_LOG_REPORT(G3D, "Failed to compile depthDownloadProgram! This shouldn't happen.\n%s", errorString.c_str());
|
||||
}
|
||||
if (!depthReadbackPipeline_) {
|
||||
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
|
||||
|
||||
ShaderModule *depthReadbackFs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)depth_dl_fs, strlen(depth_dl_fs), "depth_dl_fs");
|
||||
ShaderModule *depthReadbackVs = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)depth_vs, strlen(depth_vs), "depth_vs");
|
||||
_assert_(depthReadbackFs && depthReadbackVs);
|
||||
|
||||
InputLayoutDesc desc = {
|
||||
{
|
||||
{ 8, false },
|
||||
},
|
||||
{
|
||||
{ 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 },
|
||||
},
|
||||
};
|
||||
InputLayout *inputLayout = draw_->CreateInputLayout(desc);
|
||||
|
||||
BlendState *blendOff = draw_->CreateBlendState({ false, 0xF });
|
||||
DepthStencilState *stencilIgnore = draw_->CreateDepthStencilState({});
|
||||
RasterState *rasterNoCull = draw_->CreateRasterState({});
|
||||
|
||||
PipelineDesc depthReadbackDesc{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{ depthReadbackVs, depthReadbackFs },
|
||||
inputLayout, stencilIgnore, blendOff, rasterNoCull, &depthUBDesc,
|
||||
};
|
||||
depthReadbackPipeline_ = draw_->CreateGraphicsPipeline(depthReadbackDesc, "depth_dl");
|
||||
_assert_(depthReadbackPipeline_);
|
||||
|
||||
rasterNoCull->Release();
|
||||
blendOff->Release();
|
||||
stencilIgnore->Release();
|
||||
inputLayout->Release();
|
||||
|
||||
depthReadbackFs->Release();
|
||||
depthReadbackVs->Release();
|
||||
|
||||
SamplerStateDesc descNearest{};
|
||||
depthReadbackSampler_ = draw_->CreateSamplerState(descNearest);
|
||||
}
|
||||
|
||||
shaderManager_->DirtyLastShader();
|
||||
auto *blitFBO = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight);
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "ReadbackDepthbufferSync");
|
||||
render->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f });
|
||||
auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height());
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync");
|
||||
Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
|
||||
// We must bind the program after starting the render pass, and set the color mask after clearing.
|
||||
render->SetScissor({ 0, 0, vfb->renderWidth, vfb->renderHeight });
|
||||
render->SetDepth(false, false, GL_ALWAYS);
|
||||
render->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE);
|
||||
render->BindProgram(depthDownloadProgram_);
|
||||
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0);
|
||||
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &depthReadbackSampler_);
|
||||
|
||||
// We must bind the program after starting the render pass.
|
||||
draw_->SetScissorRect(0, 0, w, h);
|
||||
draw_->BindPipeline(depthReadbackPipeline_);
|
||||
|
||||
DepthUB ub{};
|
||||
|
||||
if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) {
|
||||
float factors[] = { 0.0f, 1.0f };
|
||||
render->SetUniformF(&u_depthDownloadFactor, 2, factors);
|
||||
// Don't scale anything, since we're not using factors outside accurate mode.
|
||||
ub.u_depthFactor[0] = 0.0f;
|
||||
ub.u_depthFactor[1] = 1.0f;
|
||||
} else {
|
||||
const float factor = DepthSliceFactor();
|
||||
float factors[] = { -0.5f * (factor - 1.0f) * (1.0f / factor), factor };
|
||||
render->SetUniformF(&u_depthDownloadFactor, 2, factors);
|
||||
ub.u_depthFactor[0] = -0.5f * (factor - 1.0f) * (1.0f / factor);
|
||||
ub.u_depthFactor[1] = factor;
|
||||
}
|
||||
float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f };
|
||||
render->SetUniformF(&u_depthDownloadShift, 4, shifts);
|
||||
float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f };
|
||||
render->SetUniformF(&u_depthDownloadTo8, 4, to8);
|
||||
static constexpr float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f };
|
||||
memcpy(ub.u_depthShift, shifts, sizeof(shifts));
|
||||
static constexpr float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f };
|
||||
memcpy(ub.u_depthTo8, to8, sizeof(to8));
|
||||
|
||||
draw_->BindFramebufferAsTexture(vfb->fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0);
|
||||
float u1 = 1.0f;
|
||||
float v1 = 1.0f;
|
||||
DrawActiveTexture(x, y, w, h, vfb->renderWidth, vfb->renderHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST);
|
||||
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
|
||||
|
||||
draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, 0, y, packWidth, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, vfb->z_stride, "ReadbackDepthbufferSync");
|
||||
// Fullscreen triangle coordinates.
|
||||
static const float positions[6] = {
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
0.0, 1.0,
|
||||
};
|
||||
draw_->DrawUP(positions, 3);
|
||||
|
||||
draw_->CopyFramebufferToMemorySync(blitFBO, FB_COLOR_BIT, x, y, w, h, DataFormat::R8G8B8A8_UNORM, convBuf_, w, "ReadbackDepthbufferSync");
|
||||
|
||||
textureCache_->ForgetLastTexture();
|
||||
// TODO: Use 4444 so we can copy lines directly?
|
||||
// TODO: Use 4444 so we can copy lines directly (instead of 32 -> 16 on CPU)?
|
||||
format16Bit = true;
|
||||
} else {
|
||||
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride, "ReadbackDepthbufferSync");
|
||||
draw_->CopyFramebufferToMemorySync(fbo, FB_DEPTH_BIT, x, y, w, h, DataFormat::D32F, convBuf_, w, "ReadbackDepthbufferSync");
|
||||
format16Bit = false;
|
||||
}
|
||||
|
||||
int dstByteOffset = y * vfb->z_stride * sizeof(u16);
|
||||
u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset);
|
||||
u32_le *packed32 = (u32_le *)convBuf_;
|
||||
GLfloat *packedf = (GLfloat *)convBuf_;
|
||||
|
||||
int totalPixels = h == 1 ? packWidth : vfb->z_stride * h;
|
||||
if (format16Bit) {
|
||||
// TODO: We have to apply GetDepthScaleFactors here too, right?
|
||||
// In this case, we used the shader to apply depth scale factors.
|
||||
uint16_t *dest = pixels;
|
||||
const u32_le *packed32 = (u32_le *)convBuf_;
|
||||
for (int yp = 0; yp < h; ++yp) {
|
||||
int row_offset = vfb->z_stride * yp;
|
||||
for (int xp = 0; xp < packWidth; ++xp) {
|
||||
const int i = row_offset + xp;
|
||||
depth[i] = packed32[i] & 0xFFFF;
|
||||
for (int xp = 0; xp < w; ++xp) {
|
||||
dest[xp] = packed32[xp] & 0xFFFF;
|
||||
}
|
||||
dest += pixelsStride;
|
||||
packed32 += w;
|
||||
}
|
||||
} else {
|
||||
// TODO: Apply this in the shader.
|
||||
// TODO: Apply this in the shader? May have precision issues if it becomes important to match.
|
||||
// We downloaded float values directly in this case.
|
||||
uint16_t *dest = pixels;
|
||||
const GLfloat *packedf = (GLfloat *)convBuf_;
|
||||
DepthScaleFactors depthScale = GetDepthScaleFactors();
|
||||
for (int yp = 0; yp < h; ++yp) {
|
||||
int row_offset = vfb->z_stride * yp;
|
||||
for (int xp = 0; xp < packWidth; ++xp) {
|
||||
const int i = row_offset + xp;
|
||||
float scaled = depthScale.Apply(packedf[i]);
|
||||
for (int xp = 0; xp < w; ++xp) {
|
||||
float scaled = depthScale.Apply(packedf[xp]);
|
||||
if (scaled <= 0.0f) {
|
||||
depth[i] = 0;
|
||||
dest[xp] = 0;
|
||||
} else if (scaled >= 65535.0f) {
|
||||
depth[i] = 65535;
|
||||
dest[xp] = 65535;
|
||||
} else {
|
||||
depth[i] = (int)scaled;
|
||||
dest[xp] = (int)scaled;
|
||||
}
|
||||
}
|
||||
dest += pixelsStride;
|
||||
packedf += w;
|
||||
}
|
||||
}
|
||||
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
protected:
|
||||
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
|
||||
void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;
|
||||
bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) override;
|
||||
|
||||
private:
|
||||
u8 *convBuf_ = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user