mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #15858 from hrydgard/copy-color-to-depth
Copy color to depth, defer depth buffer copies
This commit is contained in:
commit
044b8d6479
22 changed files with 207 additions and 253 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "GPU/Common/FramebufferManagerCommon.h"
|
||||
#include "GPU/Common/TextureCacheCommon.h"
|
||||
#include "GPU/Common/GPUStateUtils.h"
|
||||
|
||||
static const InputDef inputs[2] = {
|
||||
{ "vec2", "a_position", Draw::SEM_POSITION },
|
||||
|
@ -58,6 +59,20 @@ RasterChannel GenerateDraw2DDepthFs(ShaderWriter &writer) {
|
|||
return RASTER_DEPTH;
|
||||
}
|
||||
|
||||
RasterChannel GenerateDraw2D565ToDepthFs(ShaderWriter &writer) {
|
||||
writer.DeclareSamplers(samplers);
|
||||
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_WRITEDEPTH);
|
||||
writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n");
|
||||
// Unlike when just copying a depth buffer, here we're generating new depth values so we'll
|
||||
// have to apply the scaling.
|
||||
DepthScaleFactors factors = GetDepthScaleFactors();
|
||||
writer.C(" vec3 rgb = ").SampleTexture2D("tex", "v_texcoord.xy").C(".xyz;\n");
|
||||
writer.F(" highp float depthValue = (floor(rgb.x * 31.99) + floor(rgb.y * 63.99) * 32.0 + floor(rgb.z * 31.99) * 2048.0); \n");
|
||||
writer.F(" gl_FragDepth = (depthValue / %f) + %f;\n", factors.scale, factors.offset);
|
||||
writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH);
|
||||
return RASTER_DEPTH;
|
||||
}
|
||||
|
||||
void GenerateDraw2DVS(ShaderWriter &writer) {
|
||||
writer.BeginVSMain(inputs, Slice<UniformDef>::empty(), varyings);
|
||||
|
||||
|
@ -159,31 +174,44 @@ Draw::Pipeline *FramebufferManagerCommon::Create2DPipeline(RasterChannel (*gener
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel) {
|
||||
void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DShader shader) {
|
||||
using namespace Draw;
|
||||
|
||||
Ensure2DResources();
|
||||
|
||||
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
|
||||
|
||||
switch (channel) {
|
||||
case RASTER_COLOR:
|
||||
switch (shader) {
|
||||
case DRAW2D_COPY_COLOR:
|
||||
if (!draw2DPipelineColor_) {
|
||||
draw2DPipelineColor_ = Create2DPipeline(&GenerateDraw2DFs);
|
||||
}
|
||||
draw_->BindPipeline(draw2DPipelineColor_);
|
||||
break;
|
||||
|
||||
case RASTER_DEPTH:
|
||||
case DRAW2D_COPY_DEPTH:
|
||||
if (!draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) {
|
||||
// Can't do it
|
||||
return;
|
||||
}
|
||||
if (!draw2DPipelineDepth_) {
|
||||
draw2DPipelineDepth_ = Create2DPipeline(&GenerateDraw2DDepthFs);
|
||||
linearFilter = false;
|
||||
}
|
||||
draw_->BindPipeline(draw2DPipelineDepth_);
|
||||
break;
|
||||
|
||||
case DRAW2D_565_TO_DEPTH:
|
||||
if (!draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) {
|
||||
// Can't do it
|
||||
return;
|
||||
}
|
||||
if (!draw2DPipeline565ToDepth_) {
|
||||
draw2DPipeline565ToDepth_ = Create2DPipeline(&GenerateDraw2D565ToDepthFs);
|
||||
linearFilter = false;
|
||||
}
|
||||
draw_->BindPipeline(draw2DPipeline565ToDepth_);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tex) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "GPU/GPU.h"
|
||||
|
||||
// For framebuffer copies and similar things that just require passthrough.
|
||||
struct Draw2DVertex {
|
||||
float x;
|
||||
|
@ -7,3 +9,20 @@ struct Draw2DVertex {
|
|||
float u;
|
||||
float v;
|
||||
};
|
||||
|
||||
enum Draw2DShader {
|
||||
DRAW2D_COPY_COLOR,
|
||||
DRAW2D_COPY_DEPTH,
|
||||
DRAW2D_565_TO_DEPTH,
|
||||
};
|
||||
|
||||
inline RasterChannel Draw2DSourceChannel(Draw2DShader shader) {
|
||||
switch (shader) {
|
||||
case DRAW2D_COPY_DEPTH:
|
||||
return RASTER_DEPTH;
|
||||
case DRAW2D_COPY_COLOR:
|
||||
case DRAW2D_565_TO_DEPTH:
|
||||
default:
|
||||
return RASTER_COLOR;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
bool shaderDepal = id.Bit(FS_BIT_SHADER_DEPAL) && !texture3D; // combination with texture3D not supported. Enforced elsewhere too.
|
||||
bool bgraTexture = id.Bit(FS_BIT_BGRA_TEXTURE);
|
||||
bool colorWriteMask = id.Bit(FS_BIT_COLOR_WRITEMASK) && compat.bitwiseOps;
|
||||
bool colorToDepth = id.Bit(FS_BIT_COLOR_TO_DEPTH);
|
||||
|
||||
GEComparison alphaTestFunc = (GEComparison)id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3);
|
||||
GEComparison colorTestFunc = (GEComparison)id.Bits(FS_BIT_COLOR_TEST_FUNC, 2);
|
||||
|
@ -123,7 +122,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
bool readFramebufferTex = readFramebuffer && !gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH);
|
||||
|
||||
bool needFragCoord = readFramebuffer || gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT);
|
||||
bool writeDepth = gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) || colorToDepth;
|
||||
bool writeDepth = gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT);
|
||||
|
||||
if (shaderDepal && !doTexture) {
|
||||
*errorString = "depal requires a texture";
|
||||
|
@ -136,11 +135,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
}
|
||||
|
||||
if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN) {
|
||||
if (colorToDepth) {
|
||||
WRITE(p, "precision highp int;\n");
|
||||
WRITE(p, "precision highp float;\n");
|
||||
}
|
||||
|
||||
if (useDiscardStencilBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n");
|
||||
}
|
||||
|
@ -293,7 +287,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
WRITE(p, "};\n");
|
||||
}
|
||||
} else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
|
||||
if ((shaderDepal || colorWriteMask || colorToDepth) && gl_extensions.IsGLES) {
|
||||
if ((shaderDepal || colorWriteMask) && gl_extensions.IsGLES) {
|
||||
WRITE(p, "precision highp int;\n");
|
||||
}
|
||||
|
||||
|
@ -461,9 +455,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
WRITE(p, "PS_OUT main( PS_IN In ) {\n");
|
||||
WRITE(p, " PS_OUT outfragment;\n");
|
||||
WRITE(p, " vec4 target;\n");
|
||||
if (colorToDepth) {
|
||||
WRITE(p, " float gl_FragDepth;\n");
|
||||
}
|
||||
} else {
|
||||
WRITE(p, "void main() {\n");
|
||||
}
|
||||
|
@ -1070,22 +1061,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
WRITE(p, " %s = vec4(0.0, 0.0, 0.0, %s.z); // blue to alpha\n", compat.fragColor0, compat.fragColor0);
|
||||
}
|
||||
|
||||
if (colorToDepth) {
|
||||
DepthScaleFactors factors = GetDepthScaleFactors();
|
||||
|
||||
if (compat.bitwiseOps) {
|
||||
WRITE(p, " highp float depthValue = float(int(%s.x * 31.99) | (int(%s.y * 63.99) << 5) | (int(%s.z * 31.99) << 11)) / 65535.0;\n", "v", "v", "v"); // compat.fragColor0, compat.fragColor0, compat.fragColor0);
|
||||
} else {
|
||||
// D3D9-compatible alternative
|
||||
WRITE(p, " highp float depthValue = (floor(%s.x * 31.99) + floor(%s.y * 63.99) * 32.0 + floor(%s.z * 31.99) * 2048.0) / 65535.0;\n", "v", "v", "v"); // compat.fragColor0, compat.fragColor0, compat.fragColor0);
|
||||
}
|
||||
if (factors.scale != 1.0 || factors.offset != 0.0) {
|
||||
WRITE(p, " gl_FragDepth = (depthValue / %f) + %f;\n", factors.scale / 65535.0f, factors.offset);
|
||||
} else {
|
||||
WRITE(p, " gl_FragDepth = depthValue;\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
const double scale = DepthSliceFactor() * 65535.0;
|
||||
|
||||
|
|
|
@ -280,8 +280,6 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
WARN_LOG_ONCE(color_equal_z, G3D, "Framebuffer bound with color addr == z addr, likely will not use Z in this pass: %08x", params.fb_address);
|
||||
}
|
||||
|
||||
RasterMode mode = RASTER_MODE_NORMAL;
|
||||
|
||||
// Find a matching framebuffer
|
||||
VirtualFramebuffer *vfb = nullptr;
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
|
@ -318,21 +316,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
vfb->height = drawing_height;
|
||||
}
|
||||
break;
|
||||
} else if (params.fb_address == v->z_address && params.fmt != GE_FORMAT_8888 && params.fb_stride == v->z_stride && !params.isBlending) {
|
||||
// Looks like the game might be intending to use color to write directly to a Z buffer.
|
||||
// This is seen in Kuroyou 2.
|
||||
|
||||
// Ignore this in this loop, BUT, we do a lookup in the depth tracking afterwards to
|
||||
// make sure we get the latest one.
|
||||
WARN_LOG_ONCE(color_matches_z, G3D, "Color framebuffer bound at %08x with likely intent to write explicit Z values using color. fmt = %s", params.fb_address, GeBufferFormatToString(params.fmt));
|
||||
// Seems impractical to use the other 16-bit formats for this due to the limited control over alpha,
|
||||
// so we'll simply only support 565.
|
||||
if (params.fmt == GE_FORMAT_565) {
|
||||
mode = RASTER_MODE_COLOR_TO_DEPTH;
|
||||
break;
|
||||
}
|
||||
} else if (v->fb_stride == params.fb_stride && v->format == params.fmt) {
|
||||
u32 v_fb_first_line_end_ptr = v->fb_address + v->fb_stride * 4; // This should be * bpp, but leaving like this until after 1.13 to be safe. The God of War games use this for shadows.
|
||||
u32 v_fb_first_line_end_ptr = v->fb_address + v->fb_stride * bpp;
|
||||
u32 v_fb_end_ptr = v->fb_address + v->fb_stride * v->height * bpp;
|
||||
|
||||
if (params.fb_address > v->fb_address && params.fb_address < v_fb_first_line_end_ptr) {
|
||||
|
@ -368,19 +353,6 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
}
|
||||
}
|
||||
|
||||
if (mode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
// Lookup in the depth tracking to find which VFB has the latest version of this Z buffer.
|
||||
// Then bind it in color-to-depth mode.
|
||||
//
|
||||
// We do this by having a special render mode where we take color and move to
|
||||
// depth in the fragment shader, and set color writes to off.
|
||||
//
|
||||
// We use a special fragment shader flag to convert color to depth.
|
||||
vfb = GetLatestDepthBufferAt(params.fb_address /* !!! */, params.fb_stride);
|
||||
}
|
||||
|
||||
gstate_c.SetFramebufferRenderMode(mode);
|
||||
|
||||
if (vfb) {
|
||||
if ((drawing_width != vfb->bufferWidth || drawing_height != vfb->bufferHeight)) {
|
||||
// Even if it's not newly wrong, if this is larger we need to resize up.
|
||||
|
@ -416,6 +388,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
|
||||
// None found? Create one.
|
||||
if (!vfb) {
|
||||
gstate_c.usingDepth = false; // reset depth buffer tracking
|
||||
|
||||
vfb = new VirtualFramebuffer{};
|
||||
vfb->fbo = nullptr;
|
||||
vfb->fb_address = params.fb_address;
|
||||
|
@ -431,7 +405,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
vfb->lastFrameNewSize = gpuStats.numFlips;
|
||||
vfb->format = params.fmt;
|
||||
vfb->drawnFormat = params.fmt;
|
||||
vfb->usageFlags = FB_USAGE_RENDERTARGET;
|
||||
vfb->usageFlags = FB_USAGE_RENDER_COLOR;
|
||||
|
||||
u32 byteSize = ColorBufferByteSize(vfb);
|
||||
if (Memory::IsVRAMAddress(params.fb_address) && params.fb_address + byteSize > framebufRangeEnd_) {
|
||||
|
@ -442,16 +416,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
ResizeFramebufFBO(vfb, drawing_width, drawing_height, true);
|
||||
NotifyRenderFramebufferCreated(vfb);
|
||||
|
||||
// Looks up by z_address, so if one is found here and not have last pointers equal to this one,
|
||||
// there is another one.
|
||||
VirtualFramebuffer *prevDepth = GetLatestDepthBufferAt(vfb->z_address, vfb->z_stride);
|
||||
|
||||
// We might already want to copy depth, in case this is a temp buffer. See #7810.
|
||||
if (prevDepth != vfb) {
|
||||
if (!params.isClearingDepth && prevDepth) {
|
||||
BlitFramebufferDepth(prevDepth, vfb);
|
||||
}
|
||||
}
|
||||
// Note that we do not even think about depth right now.
|
||||
|
||||
SetColorUpdated(vfb, skipDrawReason);
|
||||
|
||||
|
@ -489,18 +454,18 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
} else if (vfbs_[i]->z_stride != 0 && params.z_address == vfbs_[i]->z_address && params.fb_address != vfbs_[i]->fb_address && !sharingReported) {
|
||||
// This happens a lot, but virtually always it's cleared.
|
||||
// It's possible the other might not clear, but when every game is reported it's not useful.
|
||||
if (params.isWritingDepth) {
|
||||
if (params.isWritingDepth && (vfbs_[i]->usageFlags & FB_USAGE_RENDER_DEPTH)) {
|
||||
WARN_LOG(SCEGE, "FBO reusing depthbuffer, c=%08x/d=%08x and c=%08x/d=%08x", params.fb_address, params.z_address, vfbs_[i]->fb_address, vfbs_[i]->z_address);
|
||||
sharingReported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We already have it!
|
||||
// We already have it!
|
||||
} else if (vfb != currentRenderVfb_) {
|
||||
// Use it as a render target.
|
||||
DEBUG_LOG(FRAMEBUF, "Switching render target to FBO for %08x: %d x %d x %d ", vfb->fb_address, vfb->width, vfb->height, vfb->format);
|
||||
vfb->usageFlags |= FB_USAGE_RENDERTARGET;
|
||||
vfb->usageFlags |= FB_USAGE_RENDER_COLOR;
|
||||
vfb->last_frame_render = gpuStats.numFlips;
|
||||
frameLastFramebufUsed_ = gpuStats.numFlips;
|
||||
vfb->dirtyAfterDisplay = true;
|
||||
|
@ -510,18 +475,19 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
VirtualFramebuffer *prev = currentRenderVfb_;
|
||||
currentRenderVfb_ = vfb;
|
||||
NotifyRenderFramebufferSwitched(prev, vfb, params.isClearingDepth);
|
||||
gstate_c.usingDepth = false; // reset depth buffer tracking
|
||||
} else {
|
||||
// Something changed, but we still got the same framebuffer we were already rendering to.
|
||||
// Might not be a lot to do here, we check in NotifyRenderFramebufferUpdated
|
||||
vfb->last_frame_render = gpuStats.numFlips;
|
||||
frameLastFramebufUsed_ = gpuStats.numFlips;
|
||||
vfb->dirtyAfterDisplay = true;
|
||||
if ((skipDrawReason & SKIPDRAW_SKIPFRAME) == 0)
|
||||
vfb->reallyDirtyAfterDisplay = true;
|
||||
|
||||
NotifyRenderFramebufferUpdated(vfb, vfbFormatChanged);
|
||||
}
|
||||
|
||||
vfb->colorBindSeq = GetBindSeqCount();
|
||||
vfb->depthBindSeq = GetBindSeqCount();
|
||||
|
||||
gstate_c.curRTWidth = vfb->width;
|
||||
gstate_c.curRTHeight = vfb->height;
|
||||
|
@ -530,6 +496,79 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
return vfb;
|
||||
}
|
||||
|
||||
// Called on the first use of depth in a render pass.
|
||||
void FramebufferManagerCommon::SetDepthFrameBuffer(bool isClearingDepth) {
|
||||
if (!currentRenderVfb_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this first draw call is anything other than a clear, "resolve" the depth buffer,
|
||||
// by copying from any overlapping buffers with fresher content.
|
||||
if (!isClearingDepth) {
|
||||
CopyToDepthFromOverlappingFramebuffers(currentRenderVfb_);
|
||||
}
|
||||
|
||||
currentRenderVfb_->usageFlags |= FB_USAGE_RENDER_DEPTH;
|
||||
currentRenderVfb_->depthBindSeq = GetBindSeqCount();
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFramebuffer *dest) {
|
||||
struct CopySource {
|
||||
VirtualFramebuffer *vfb;
|
||||
RasterChannel channel;
|
||||
|
||||
int seq() const {
|
||||
return channel == RASTER_DEPTH ? vfb->depthBindSeq : vfb->colorBindSeq;
|
||||
}
|
||||
|
||||
bool operator < (const CopySource &other) const {
|
||||
return seq() < other.seq();
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<CopySource> sources;
|
||||
for (auto src : vfbs_) {
|
||||
if (src == dest)
|
||||
continue;
|
||||
|
||||
if (src->fb_address == dest->z_address && src->fb_stride == dest->z_stride && src->format == GE_FORMAT_565) {
|
||||
if (src->colorBindSeq > dest->depthBindSeq) {
|
||||
// Source has newer data than the current buffer, use it.
|
||||
sources.push_back(CopySource{ src, RASTER_COLOR });
|
||||
}
|
||||
} else if (src->z_address == dest->z_address && src->z_stride == dest->z_stride && src->depthBindSeq > dest->depthBindSeq) {
|
||||
// Don't bother if the buffer was from another frame. This heuristic is old.
|
||||
sources.push_back(CopySource{ src, RASTER_DEPTH });
|
||||
} else {
|
||||
// TODO: Do more detailed overlap checks here.
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(sources.begin(), sources.end());
|
||||
|
||||
// TODO: A full copy will overwrite anything else. So we can eliminate
|
||||
// anything that comes before such a copy.
|
||||
|
||||
// For now, let's just do the last thing, if there are multiple.
|
||||
|
||||
// for (auto &source : sources) {
|
||||
if (sources.size()) {
|
||||
auto &source = sources.back();
|
||||
if (source.channel == RASTER_DEPTH) {
|
||||
// Good old depth->depth copy.
|
||||
BlitFramebufferDepth(source.vfb, dest);
|
||||
gpuStats.numDepthCopies++;
|
||||
dest->last_frame_depth_updated = gpuStats.numFlips;
|
||||
} else if (source.channel == RASTER_COLOR) {
|
||||
VirtualFramebuffer *src = source.vfb;
|
||||
// Copying color to depth.
|
||||
BlitUsingRaster(src->fbo, 0.0f, 0.0f, src->renderWidth, src->renderHeight, dest->fbo, 0.0f, 0.0f, dest->renderWidth, dest->renderHeight, false, DRAW2D_565_TO_DEPTH, "565_to_depth");
|
||||
}
|
||||
}
|
||||
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
|
||||
// Notify the texture cache of both the color and depth buffers.
|
||||
textureCache_->NotifyFramebuffer(v, NOTIFY_FB_DESTROYED);
|
||||
|
@ -600,25 +639,10 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
|
|||
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth");
|
||||
RebindFramebuffer("After BlitFramebufferDepth");
|
||||
} else if (useRaster) {
|
||||
BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, RasterChannel::RASTER_DEPTH);
|
||||
BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, Draw2DShader::DRAW2D_COPY_DEPTH, "BlitDepthRaster");
|
||||
}
|
||||
|
||||
draw_->InvalidateCachedState();
|
||||
|
||||
gpuStats.numDepthCopies++;
|
||||
dst->last_frame_depth_updated = gpuStats.numFlips;
|
||||
}
|
||||
|
||||
VirtualFramebuffer *FramebufferManagerCommon::GetLatestDepthBufferAt(u32 z_address, u16 z_stride) {
|
||||
int maxSeq = -1;
|
||||
VirtualFramebuffer *latestDepth = nullptr;
|
||||
for (auto vfb : vfbs_) {
|
||||
if (vfb->z_address == z_address && vfb->z_stride == z_stride && vfb->depthBindSeq > maxSeq) {
|
||||
maxSeq = vfb->depthBindSeq;
|
||||
latestDepth = vfb;
|
||||
}
|
||||
}
|
||||
return latestDepth;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) {
|
||||
|
@ -669,17 +693,6 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
|
|||
textureCache_->ForgetLastTexture();
|
||||
shaderManager_->DirtyLastShader();
|
||||
|
||||
// Copy depth between the framebuffers, if the z_address is the same (checked inside.)
|
||||
VirtualFramebuffer * prevDepth = GetLatestDepthBufferAt(vfb->z_address, vfb->z_stride);
|
||||
|
||||
// We might already want to copy depth, in case this is a temp buffer. See #7810.
|
||||
if (prevDepth != vfb) {
|
||||
if (!isClearingDepth && prevDepth) {
|
||||
BlitFramebufferDepth(prevDepth, vfb);
|
||||
}
|
||||
prevDepth = vfb;
|
||||
}
|
||||
|
||||
if (vfb->drawnFormat != vfb->format) {
|
||||
ReinterpretFramebuffer(vfb, vfb->drawnFormat, vfb->format);
|
||||
}
|
||||
|
@ -1564,7 +1577,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd
|
|||
vfb->bufferHeight = vfb->height;
|
||||
vfb->format = format;
|
||||
vfb->drawnFormat = GE_FORMAT_8888;
|
||||
vfb->usageFlags = FB_USAGE_RENDERTARGET;
|
||||
vfb->usageFlags = FB_USAGE_RENDER_COLOR;
|
||||
SetColorUpdated(vfb, 0);
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address);
|
||||
|
@ -1632,7 +1645,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram
|
|||
UpdateDownloadTempBuffer(nvfb);
|
||||
}
|
||||
|
||||
nvfb->usageFlags |= FB_USAGE_RENDERTARGET;
|
||||
nvfb->usageFlags |= FB_USAGE_RENDER_COLOR;
|
||||
nvfb->last_frame_render = gpuStats.numFlips;
|
||||
nvfb->dirtyAfterDisplay = true;
|
||||
|
||||
|
@ -1949,7 +1962,7 @@ void FramebufferManagerCommon::UpdateFramebufUsage(VirtualFramebuffer *vfb) {
|
|||
|
||||
checkFlag(FB_USAGE_DISPLAYED_FRAMEBUFFER, vfb->last_frame_displayed);
|
||||
checkFlag(FB_USAGE_TEXTURE, vfb->last_frame_used);
|
||||
checkFlag(FB_USAGE_RENDERTARGET, vfb->last_frame_render);
|
||||
checkFlag(FB_USAGE_RENDER_COLOR, vfb->last_frame_render);
|
||||
checkFlag(FB_USAGE_CLUT, vfb->last_frame_clut);
|
||||
}
|
||||
|
||||
|
@ -2327,6 +2340,7 @@ void FramebufferManagerCommon::DeviceLost() {
|
|||
DoRelease(draw2DVs_);
|
||||
DoRelease(draw2DPipelineColor_);
|
||||
DoRelease(draw2DPipelineDepth_);
|
||||
DoRelease(draw2DPipeline565ToDepth_);
|
||||
|
||||
draw_ = nullptr;
|
||||
}
|
||||
|
@ -2384,7 +2398,7 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa
|
|||
// Rearrange to strip form.
|
||||
std::swap(coord[2], coord[3]);
|
||||
|
||||
DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0, RASTER_COLOR);
|
||||
DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0, DRAW2D_COPY_COLOR);
|
||||
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
|
||||
}
|
||||
|
@ -2480,13 +2494,14 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX
|
|||
draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2,
|
||||
channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, tag);
|
||||
} else {
|
||||
Draw2DShader shader = channel == RASTER_COLOR ? DRAW2D_COPY_COLOR : DRAW2D_COPY_DEPTH;
|
||||
Draw::Framebuffer *srcFBO = src->fbo;
|
||||
if (src == dst) {
|
||||
Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::BLIT, src->renderWidth, src->renderHeight);
|
||||
BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, false, channel);
|
||||
BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, false, shader, tag);
|
||||
srcFBO = tempFBO;
|
||||
}
|
||||
BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false, channel);
|
||||
BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false, shader, tag);
|
||||
}
|
||||
|
||||
draw_->InvalidateCachedState();
|
||||
|
@ -2498,9 +2513,9 @@ void FramebufferManagerCommon::BlitUsingRaster(
|
|||
Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2,
|
||||
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2,
|
||||
bool linearFilter,
|
||||
RasterChannel channel) {
|
||||
Draw2DShader shader, const char *tag) {
|
||||
|
||||
if (channel == RASTER_DEPTH) {
|
||||
if (shader == DRAW2D_COPY_DEPTH || shader == DRAW2D_565_TO_DEPTH) {
|
||||
_dbg_assert_(draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported);
|
||||
}
|
||||
|
||||
|
@ -2522,13 +2537,13 @@ void FramebufferManagerCommon::BlitUsingRaster(
|
|||
// Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily).
|
||||
draw_->BindTexture(0, nullptr);
|
||||
// This will get optimized away in case it's already bound (in VK and GL at least..)
|
||||
draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitUsingRaster");
|
||||
draw_->BindFramebufferAsTexture(src, 0, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0);
|
||||
draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster");
|
||||
draw_->BindFramebufferAsTexture(src, 0, Draw2DSourceChannel(shader) == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0);
|
||||
|
||||
Draw::Viewport vp{ 0.0f, 0.0f, (float)dest->Width(), (float)dest->Height(), 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &vp);
|
||||
draw_->SetScissorRect(0, 0, (int)dest->Width(), (int)dest->Height());
|
||||
DrawStrip2D(nullptr, vtx, 4, linearFilter, channel);
|
||||
DrawStrip2D(nullptr, vtx, 4, linearFilter, shader);
|
||||
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
|
||||
}
|
||||
|
|
|
@ -37,13 +37,14 @@
|
|||
|
||||
enum {
|
||||
FB_USAGE_DISPLAYED_FRAMEBUFFER = 1,
|
||||
FB_USAGE_RENDERTARGET = 2,
|
||||
FB_USAGE_RENDER_COLOR = 2,
|
||||
FB_USAGE_TEXTURE = 4,
|
||||
FB_USAGE_CLUT = 8,
|
||||
FB_USAGE_DOWNLOAD = 16,
|
||||
FB_USAGE_DOWNLOAD_CLEAR = 32,
|
||||
FB_USAGE_BLUE_TO_ALPHA = 64,
|
||||
FB_USAGE_FIRST_FRAME_SAVED = 128,
|
||||
FB_USAGE_RENDER_DEPTH = 256,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -266,6 +267,8 @@ public:
|
|||
return vfb;
|
||||
}
|
||||
}
|
||||
void SetDepthFrameBuffer(bool isClearingDepth);
|
||||
|
||||
void RebindFramebuffer(const char *tag);
|
||||
std::vector<FramebufferInfo> GetFramebufferList() const;
|
||||
|
||||
|
@ -288,8 +291,6 @@ public:
|
|||
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
|
||||
void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride);
|
||||
|
||||
VirtualFramebuffer *GetLatestDepthBufferAt(u32 z_address, u16 z_stride);
|
||||
|
||||
void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
|
||||
|
||||
size_t NumVFBs() const { return vfbs_.size(); }
|
||||
|
@ -342,12 +343,6 @@ public:
|
|||
int GetTargetStride() const { return currentRenderVfb_ ? currentRenderVfb_->fb_stride : 512; }
|
||||
GEBufferFormat GetTargetFormat() const { return currentRenderVfb_ ? currentRenderVfb_->format : displayFormat_; }
|
||||
|
||||
void SetDepthUpdated() {
|
||||
if (currentRenderVfb_) {
|
||||
currentRenderVfb_->last_frame_depth_render = gpuStats.numFlips;
|
||||
currentRenderVfb_->last_frame_depth_updated = gpuStats.numFlips;
|
||||
}
|
||||
}
|
||||
void SetColorUpdated(int skipDrawReason) {
|
||||
if (currentRenderVfb_) {
|
||||
SetColorUpdated(currentRenderVfb_, skipDrawReason);
|
||||
|
@ -380,10 +375,12 @@ protected:
|
|||
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);
|
||||
|
||||
void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel);
|
||||
void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DShader channel);
|
||||
void Ensure2DResources();
|
||||
Draw::Pipeline *Create2DPipeline(RasterChannel (*generate)(ShaderWriter &));
|
||||
|
||||
void CopyToDepthFromOverlappingFramebuffers(VirtualFramebuffer *dest);
|
||||
|
||||
bool UpdateSize();
|
||||
|
||||
void FlushBeforeCopy();
|
||||
|
@ -394,7 +391,7 @@ protected:
|
|||
|
||||
void BlitUsingRaster(
|
||||
Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2,
|
||||
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter, RasterChannel channel);
|
||||
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter, Draw2DShader shader, const char *tag);
|
||||
|
||||
void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags);
|
||||
|
||||
|
@ -513,6 +510,7 @@ protected:
|
|||
// Draw2D pipelines
|
||||
Draw::Pipeline *draw2DPipelineColor_ = nullptr;
|
||||
Draw::Pipeline *draw2DPipelineDepth_ = nullptr;
|
||||
Draw::Pipeline *draw2DPipeline565ToDepth_ = nullptr;
|
||||
Draw::SamplerState *draw2DSamplerLinear_ = nullptr;
|
||||
Draw::SamplerState *draw2DSamplerNearest_ = nullptr;
|
||||
Draw::ShaderModule *draw2DVs_ = nullptr;
|
||||
|
|
|
@ -1018,16 +1018,6 @@ void ConvertMaskState(GenericMaskState &maskState, bool allowFramebufferRead) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
// Suppress color writes entirely in this mode.
|
||||
maskState.applyFramebufferRead = false;
|
||||
maskState.rgba[0] = false;
|
||||
maskState.rgba[1] = false;
|
||||
maskState.rgba[2] = false;
|
||||
maskState.rgba[3] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Invert to convert masks from the PSP's format where 1 is don't draw to PC where 1 is draw.
|
||||
uint32_t colorMask = ~((gstate.pmskc & 0xFFFFFF) | (gstate.pmska << 24));
|
||||
|
||||
|
|
|
@ -240,8 +240,6 @@ std::string FragmentShaderDesc(const FShaderID &id) {
|
|||
if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc << "ColorTest0 " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match;
|
||||
else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match
|
||||
|
||||
if (id.Bit(FS_BIT_COLOR_TO_DEPTH)) desc << "ColorToDepth ";
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
|
@ -264,7 +262,6 @@ void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) {
|
|||
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT;
|
||||
bool useShaderDepal = gstate_c.useShaderDepal;
|
||||
bool colorWriteMask = IsColorWriteMaskComplex(gstate_c.allowFramebufferRead);
|
||||
bool colorToDepth = gstate_c.renderMode == RasterMode::RASTER_MODE_COLOR_TO_DEPTH;
|
||||
|
||||
// Note how we here recompute some of the work already done in state mapping.
|
||||
// Not ideal! At least we share the code.
|
||||
|
@ -296,8 +293,6 @@ void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) {
|
|||
id.SetBit(FS_BIT_3D_TEXTURE, gstate_c.curTextureIs3D);
|
||||
}
|
||||
|
||||
id.SetBit(FS_BIT_COLOR_TO_DEPTH, colorToDepth);
|
||||
|
||||
id.SetBit(FS_BIT_LMODE, lmode);
|
||||
if (enableAlphaTest) {
|
||||
// 5 bits total.
|
||||
|
|
|
@ -94,7 +94,6 @@ enum FShaderBit : uint8_t {
|
|||
FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL = 49,
|
||||
FS_BIT_COLOR_WRITEMASK = 50,
|
||||
FS_BIT_3D_TEXTURE = 51,
|
||||
FS_BIT_COLOR_TO_DEPTH = 52,
|
||||
};
|
||||
|
||||
static inline FShaderBit operator +(FShaderBit bit, int i) {
|
||||
|
|
|
@ -106,13 +106,7 @@ inline int dimHeight(u16 dim) {
|
|||
// Vulkan color formats:
|
||||
// TODO
|
||||
TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw)
|
||||
: draw_(draw),
|
||||
clutLastFormat_(0xFFFFFFFF),
|
||||
clutTotalBytes_(0),
|
||||
clutMaxBytes_(0),
|
||||
clutRenderAddress_(0xFFFFFFFF),
|
||||
clutAlphaLinear_(false),
|
||||
isBgraBackend_(false) {
|
||||
: draw_(draw) {
|
||||
decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL;
|
||||
|
||||
// TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut.
|
||||
|
@ -265,10 +259,6 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac
|
|||
}
|
||||
}
|
||||
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
forceFiltering = TEX_FILTER_FORCE_NEAREST;
|
||||
}
|
||||
|
||||
switch (forceFiltering) {
|
||||
case TEX_FILTER_AUTO:
|
||||
break;
|
||||
|
@ -2247,11 +2237,6 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
|
|||
plan.scaleFactor = 1;
|
||||
}
|
||||
|
||||
// Don't upscale textures in color-to-depth mode.
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
plan.scaleFactor = 1;
|
||||
}
|
||||
|
||||
if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && plan.scaleFactor != 1 && plan.slowScaler) {
|
||||
// Remember for later that we /wanted/ to scale this texture.
|
||||
entry->status |= TexCacheEntry::STATUS_TO_SCALE;
|
||||
|
|
|
@ -444,13 +444,13 @@ protected:
|
|||
u32 *clutBufConverted_;
|
||||
// This is the active one.
|
||||
u32 *clutBuf_;
|
||||
u32 clutLastFormat_;
|
||||
u32 clutTotalBytes_;
|
||||
u32 clutMaxBytes_;
|
||||
u32 clutRenderAddress_;
|
||||
u32 clutLastFormat_ = 0xFFFFFFFF;
|
||||
u32 clutTotalBytes_ = 0;
|
||||
u32 clutMaxBytes_ = 0;
|
||||
u32 clutRenderAddress_ = 0xFFFFFFFF;
|
||||
u32 clutRenderOffset_;
|
||||
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
|
||||
bool clutAlphaLinear_;
|
||||
bool clutAlphaLinear_ = false;
|
||||
u16 clutAlphaLinearColor_;
|
||||
|
||||
int standardScaleFactor_;
|
||||
|
@ -461,7 +461,7 @@ protected:
|
|||
bool nextNeedsChange_;
|
||||
bool nextNeedsRebuild_;
|
||||
|
||||
bool isBgraBackend_;
|
||||
bool isBgraBackend_ = false;
|
||||
|
||||
u32 expandClut_[256];
|
||||
};
|
||||
|
|
|
@ -693,9 +693,6 @@ rotateVBO:
|
|||
if (gstate.isClearModeAlphaMask()) clearFlag |= Draw::FBChannel::FB_STENCIL_BIT;
|
||||
if (gstate.isClearModeDepthMask()) clearFlag |= Draw::FBChannel::FB_DEPTH_BIT;
|
||||
|
||||
if (clearFlag & Draw::FBChannel::FB_DEPTH_BIT) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
if (clearFlag & Draw::FBChannel::FB_COLOR_BIT) {
|
||||
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
|
||||
}
|
||||
|
|
|
@ -293,21 +293,11 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
|||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
// Enforce plain depth writing.
|
||||
keys_.depthStencil.value = 0;
|
||||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthWriteEnable = true;
|
||||
keys_.depthStencil.stencilTestEnable = false;
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS;
|
||||
} else if (gstate.isModeClear()) {
|
||||
if (gstate.isModeClear()) {
|
||||
keys_.depthStencil.value = 0;
|
||||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS;
|
||||
keys_.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
|
@ -336,9 +326,6 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
|||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
keys_.depthStencil.depthTestEnable = false;
|
||||
keys_.depthStencil.depthWriteEnable = false;
|
||||
|
|
|
@ -640,9 +640,6 @@ rotateVBO:
|
|||
if (gstate.isClearModeAlphaMask()) mask |= D3DCLEAR_STENCIL;
|
||||
if (gstate.isClearModeDepthMask()) mask |= D3DCLEAR_ZBUFFER;
|
||||
|
||||
if (mask & D3DCLEAR_ZBUFFER) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
if (mask & D3DCLEAR_TARGET) {
|
||||
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
|
||||
}
|
||||
|
|
|
@ -211,21 +211,11 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
|||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Set Stencil/Depth
|
||||
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
// Enforce plain depth writing.
|
||||
dxstate.depthTest.enable();
|
||||
dxstate.depthFunc.set(D3DCMP_ALWAYS);
|
||||
dxstate.depthWrite.set(true);
|
||||
dxstate.stencilTest.disable();
|
||||
} else if (gstate.isModeClear()) {
|
||||
if (gstate.isModeClear()) {
|
||||
// Depth Test
|
||||
dxstate.depthTest.enable();
|
||||
dxstate.depthFunc.set(D3DCMP_ALWAYS);
|
||||
dxstate.depthWrite.set(gstate.isClearModeDepthMask());
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
|
@ -246,9 +236,6 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
|||
dxstate.depthTest.enable();
|
||||
dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]);
|
||||
dxstate.depthWrite.set(gstate.isDepthWriteEnabled());
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
dxstate.depthTest.disable();
|
||||
}
|
||||
|
|
|
@ -423,9 +423,6 @@ void DrawEngineGLES::DoFlush() {
|
|||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
bool depthMask = gstate.isClearModeDepthMask();
|
||||
if (depthMask) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
GLbitfield target = 0;
|
||||
// Without this, we will clear RGB when clearing stencil, which breaks games.
|
||||
|
|
|
@ -251,24 +251,14 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
// Enforce plain depth writing.
|
||||
renderManager->SetStencilDisabled();
|
||||
renderManager->SetDepth(true, true, GL_ALWAYS);
|
||||
} else if (gstate.isModeClear()) {
|
||||
if (gstate.isModeClear()) {
|
||||
// Depth Test
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
renderManager->SetStencilFunc(gstate.isClearModeAlphaMask(), GL_ALWAYS, 0xFF, 0xFF);
|
||||
renderManager->SetStencilOp(stencilState.writeMask, GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
||||
renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS);
|
||||
} else {
|
||||
// Depth Test
|
||||
renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]);
|
||||
if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
|
|
|
@ -24,11 +24,6 @@ class GPUInterface;
|
|||
class GPUDebugInterface;
|
||||
class GraphicsContext;
|
||||
|
||||
enum RasterMode {
|
||||
RASTER_MODE_NORMAL = 0,
|
||||
RASTER_MODE_COLOR_TO_DEPTH = 1,
|
||||
};
|
||||
|
||||
// PSP rasterization has two outputs, color and depth. Stencil is packed
|
||||
// into the alpha channel of color (if exists), so possibly RASTER_COLOR
|
||||
// should be named RASTER_COLOR_STENCIL but it gets kinda hard to read.
|
||||
|
|
|
@ -1624,6 +1624,21 @@ void GPUCommon::Execute_VertexTypeSkinning(u32 op, u32 diff) {
|
|||
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_CULLRANGE);
|
||||
}
|
||||
|
||||
void GPUCommon::CheckDepthUsage(VirtualFramebuffer *vfb) {
|
||||
if (!gstate_c.usingDepth) {
|
||||
bool isClearingDepth = gstate.isModeClear() && gstate.isClearModeDepthMask();
|
||||
|
||||
if ((gstate.isDepthTestEnabled() || isClearingDepth)) {
|
||||
gstate_c.usingDepth = true;
|
||||
gstate_c.clearingDepth = isClearingDepth;
|
||||
vfb->last_frame_depth_render = gpuStats.numFlips;
|
||||
if (isClearingDepth || gstate.isDepthWriteEnabled()) {
|
||||
vfb->last_frame_depth_updated = gpuStats.numFlips;
|
||||
}
|
||||
framebufferManager_->SetDepthFrameBuffer(isClearingDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Prim(u32 op, u32 diff) {
|
||||
// This drives all drawing. All other state we just buffer up, then we apply it only
|
||||
|
@ -1685,6 +1700,8 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) {
|
|||
return;
|
||||
}
|
||||
|
||||
CheckDepthUsage(vfb);
|
||||
|
||||
const void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
|
||||
const void *inds = nullptr;
|
||||
u32 vertexType = gstate.vertType;
|
||||
|
@ -1883,12 +1900,14 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
|
|||
gstate_c.framebufFormat = gstate.FrameBufFormat();
|
||||
|
||||
// This also make skipping drawing very effective.
|
||||
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
|
||||
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
|
||||
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
|
||||
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
|
||||
return;
|
||||
}
|
||||
|
||||
CheckDepthUsage(vfb);
|
||||
|
||||
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
|
||||
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
|
||||
return;
|
||||
|
@ -1953,12 +1972,14 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) {
|
|||
gstate_c.framebufFormat = gstate.FrameBufFormat();
|
||||
|
||||
// This also make skipping drawing very effective.
|
||||
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
|
||||
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
|
||||
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
|
||||
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
|
||||
return;
|
||||
}
|
||||
|
||||
CheckDepthUsage(vfb);
|
||||
|
||||
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
|
||||
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
|
||||
return;
|
||||
|
|
|
@ -15,6 +15,8 @@ class FramebufferManagerCommon;
|
|||
class TextureCacheCommon;
|
||||
class DrawEngineCommon;
|
||||
class GraphicsContext;
|
||||
struct VirtualFramebuffer;
|
||||
|
||||
namespace Draw {
|
||||
class DrawContext;
|
||||
}
|
||||
|
@ -282,17 +284,11 @@ protected:
|
|||
void SlowRunLoop(DisplayList &list);
|
||||
void UpdatePC(u32 currentPC, u32 newPC);
|
||||
void UpdateState(GPURunState state);
|
||||
void PopDLQueue();
|
||||
void CheckDrawSync();
|
||||
int GetNextListIndex();
|
||||
virtual void FastLoadBoneMatrix(u32 target);
|
||||
void FastLoadBoneMatrix(u32 target);
|
||||
|
||||
// TODO: Unify this.
|
||||
virtual void FinishDeferred() {}
|
||||
|
||||
void DoBlockTransfer(u32 skipDrawReason);
|
||||
void DoExecuteCall(u32 target);
|
||||
|
||||
void AdvanceVerts(u32 vertType, int count, int bytesRead) {
|
||||
if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
|
||||
int indexShift = ((vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1;
|
||||
|
@ -362,6 +358,13 @@ protected:
|
|||
|
||||
private:
|
||||
void FlushImm();
|
||||
void CheckDepthUsage(VirtualFramebuffer *vfb);
|
||||
void DoBlockTransfer(u32 skipDrawReason);
|
||||
void DoExecuteCall(u32 target);
|
||||
void PopDLQueue();
|
||||
void CheckDrawSync();
|
||||
int GetNextListIndex();
|
||||
|
||||
// Debug stats.
|
||||
double timeSteppingStarted_;
|
||||
double timeSpentStepping_;
|
||||
|
|
|
@ -555,14 +555,6 @@ struct GPUStateCache {
|
|||
Dirty(DIRTY_FRAGMENTSHADER_STATE | (is3D ? DIRTY_MIPBIAS : 0));
|
||||
}
|
||||
}
|
||||
void SetFramebufferRenderMode(RasterMode mode) {
|
||||
if (mode != renderMode) {
|
||||
// This mode modifies the fragment shader to write depth, the depth state to write without testing, and the blend state to write nothing to color.
|
||||
// So we need to re-evaluate those states.
|
||||
Dirty(DIRTY_FRAGMENTSHADER_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_PARAMS);
|
||||
renderMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
u32 featureFlags;
|
||||
|
||||
|
@ -572,6 +564,9 @@ struct GPUStateCache {
|
|||
|
||||
uint64_t dirty;
|
||||
|
||||
bool usingDepth; // For deferred depth copies.
|
||||
bool clearingDepth;
|
||||
|
||||
bool textureFullAlpha;
|
||||
bool vertexFullAlpha;
|
||||
|
||||
|
@ -613,9 +608,6 @@ struct GPUStateCache {
|
|||
// We detect this case and go into a special drawing mode.
|
||||
bool blueToAlpha;
|
||||
|
||||
// Some games try to write to the Z buffer using color. Catch that and actually do the writes to the Z buffer instead.
|
||||
RasterMode renderMode;
|
||||
|
||||
// TODO: These should be accessed from the current VFB object directly.
|
||||
u32 curRTWidth;
|
||||
u32 curRTHeight;
|
||||
|
|
|
@ -75,7 +75,4 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo
|
|||
if (clearColor || clearAlpha) {
|
||||
SetColorUpdated(gstate_c.skipDrawReason);
|
||||
}
|
||||
if (clearDepth) {
|
||||
SetDepthUpdated();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,20 +250,10 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
|
|||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
|
||||
// Enforce plain depth writing.
|
||||
key.depthTestEnable = true;
|
||||
key.depthWriteEnable = true;
|
||||
key.stencilTestEnable = false;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.depthClampEnable = false;
|
||||
} else if (gstate.isModeClear()) {
|
||||
if (gstate.isModeClear()) {
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
fbManager.SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
|
@ -294,9 +284,6 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
|
|||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
key.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
fbManager.SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
key.depthTestEnable = false;
|
||||
key.depthWriteEnable = false;
|
||||
|
|
Loading…
Add table
Reference in a new issue