Merge pull request #15815 from hrydgard/depth-blit-using-raster

Depth blit using raster
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2022-08-09 21:02:19 +02:00
commit 3edaeae812
23 files changed
+220 -89

No files matched your search

+1
View File
@@ -269,6 +269,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
caps_.fragmentShaderInt32Supported = true;
caps_.anisoSupported = true;
caps_.textureNPOTFullySupported = true;
caps_.fragmentShaderDepthWriteSupported = true;
D3D11_FEATURE_DATA_D3D11_OPTIONS options{};
HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options));
+1
View File
@@ -669,6 +669,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID
caps_.framebufferSeparateDepthCopySupported = false;
caps_.texture3DSupported = true;
caps_.textureNPOTFullySupported = true;
caps_.fragmentShaderDepthWriteSupported = true;
if (d3d) {
D3DDISPLAYMODE displayMode;
+7
View File
@@ -560,6 +560,13 @@ OpenGLContext::OpenGLContext() {
gl_extensions.IsCoreContext || gl_extensions.GLES3 ||
gl_extensions.ARB_texture_non_power_of_two || gl_extensions.OES_texture_npot;
if (gl_extensions.IsGLES) {
caps_.fragmentShaderDepthWriteSupported = gl_extensions.GLES3;
// There's also GL_EXT_frag_depth but it's rare along with 2.0. Most chips that support it are simply 3.0 chips.
} else {
caps_.fragmentShaderDepthWriteSupported = true;
}
// Interesting potential hack for emulating GL_DEPTH_CLAMP (use a separate varying, force depth in fragment shader):
// This will induce a performance penalty on many architectures though so a blanket enable of this
// is probably not a good idea.
+38 -7
View File
@@ -212,7 +212,7 @@ void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniform
}
}
void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings, FSFlags flags) {
_assert_(this->stage_ == ShaderStage::Fragment);
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
@@ -226,29 +226,56 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> var
C("};\n");
}
if (flags & FSFLAG_WRITEDEPTH) {
C("float gl_FragDepth;\n");
}
C("struct PS_OUT {\n");
C(" vec4 target : SV_Target0;\n");
if (flags & FSFLAG_WRITEDEPTH) {
C(" float depth : SV_Depth;\n");
}
C("};\n");
// Let's do the varyings as parameters to main, no struct.
C("vec4 main(");
C("PS_OUT main(");
for (auto &varying : varyings) {
F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
}
// Erase the last comma
Rewind(2);
F(") : SV_Target0 {\n");
F(") {\n");
C(" PS_OUT ps_out;\n");
if (flags & FSFLAG_WRITEDEPTH) {
C(" float gl_FragDepth;\n");
}
break;
case HLSL_D3D9:
C("struct PS_OUT {\n");
C(" vec4 target : SV_Target0;\n");
if (flags & FSFLAG_WRITEDEPTH) {
C(" float depth : DEPTH;\n");
}
C("};\n");
for (auto &uniform : uniforms) {
F(" %s %s : register(c%d);\n", uniform.type, uniform.name, uniform.index);
}
// Let's do the varyings as parameters to main, no struct.
C("vec4 main(");
C("PS_OUT main(");
for (auto &varying : varyings) {
F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
}
// Erase the last comma
Rewind(2);
F(") : COLOR {\n");
F(") {\n");
C(" PS_OUT ps_out;\n");
if (flags & FSFLAG_WRITEDEPTH) {
C(" float gl_FragDepth;\n");
}
break;
case GLSL_VULKAN:
for (auto &varying : varyings) {
@@ -299,12 +326,16 @@ void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {
C("}\n");
}
void ShaderWriter::EndFSMain(const char *vec4_color_variable) {
void ShaderWriter::EndFSMain(const char *vec4_color_variable, FSFlags flags) {
_assert_(this->stage_ == ShaderStage::Fragment);
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
case HLSL_D3D9:
F(" return %s;\n", vec4_color_variable);
F(" ps_out.target = %s;\n", vec4_color_variable);
if (flags & FSFLAG_WRITEDEPTH) {
C(" ps_out.depth = gl_FragDepth;\n");
}
C(" return ps_out;\n");
break;
case GLSL_VULKAN:
default: // OpenGL
+7 -2
View File
@@ -36,6 +36,11 @@ struct VaryingDef {
const char *precision;
};
enum FSFlags {
FSFLAG_NONE = 0,
FSFLAG_WRITEDEPTH = 1,
};
class ShaderWriter {
public:
ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions, size_t num_gl_extensions) : p_(buffer), lang_(lang), stage_(stage) {
@@ -82,11 +87,11 @@ public:
// Simple shaders with no special tricks.
void BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniforms, Slice<VaryingDef> varyings);
void BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings);
void BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings, FSFlags flags);
// For simple shaders that output a single color, we can deal with this generically.
void EndVSMain(Slice<VaryingDef> varyings);
void EndFSMain(const char *vec4_color_variable);
void EndFSMain(const char *vec4_color_variable, FSFlags flags);
void Rewind(size_t offset) {
+1
View File
@@ -793,6 +793,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
caps_.texture3DSupported = true;
caps_.fragmentShaderInt32Supported = true;
caps_.textureNPOTFullySupported = true;
caps_.fragmentShaderDepthWriteSupported = true;
auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties;
switch (deviceProps.vendorID) {
+1
View File
@@ -541,6 +541,7 @@ struct DeviceCaps {
bool texture3DSupported;
bool fragmentShaderInt32Supported;
bool textureNPOTFullySupported;
bool fragmentShaderDepthWriteSupported;
std::string deviceName; // The device name to use when creating the thin3d context, to get the same one.
};
+2 -2
View File
@@ -267,7 +267,7 @@ void GenerateDepalFs(char *buffer, const DepalConfig &config, const ShaderLangua
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
writer.DeclareSamplers(samplers);
writer.HighPrecisionFloat();
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_NONE);
switch (lang.shaderLanguage) {
case HLSL_D3D9:
case GLSL_1xx:
@@ -281,7 +281,7 @@ void GenerateDepalFs(char *buffer, const DepalConfig &config, const ShaderLangua
default:
_assert_msg_(false, "Depal shader language not supported: %d", (int)lang.shaderLanguage);
}
writer.EndFSMain("outColor");
writer.EndFSMain("outColor", FSFLAG_NONE);
}
void GenerateDepalVs(char *buffer, const ShaderLanguageDesc &lang) {
+56 -12
View File
@@ -39,12 +39,21 @@ static const SamplerDef samplers[1] = {
{ "tex" },
};
void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) {
void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
writer.DeclareSamplers(samplers);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_NONE);
writer.C(" vec4 outColor = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n");
writer.EndFSMain("outColor");
writer.EndFSMain("outColor", FSFLAG_NONE);
}
void GenerateDraw2DDepthFs(char *buffer, const ShaderLanguageDesc &lang) {
ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
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");
writer.C(" gl_FragDepth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n");
writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH);
}
void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) {
@@ -60,15 +69,17 @@ void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) {
}
// verts have positions in clip coordinates.
void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter) {
void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel) {
using namespace Draw;
if (!draw2DPipelineLinear_) {
if (!draw2DPipelineColor_) {
const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc();
char *fsCode = new char[4000];
char *fsDepthCode = new char[4000];
char *vsCode = new char[4000];
GenerateDraw2DFs(fsCode, shaderLanguageDesc, draw_->GetBugs());
GenerateDraw2DFs(fsCode, shaderLanguageDesc);
GenerateDraw2DDepthFs(fsDepthCode, shaderLanguageDesc);
GenerateDraw2DVS(vsCode, shaderLanguageDesc);
draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs");
@@ -76,6 +87,13 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver
_assert_(draw2DFs_ && draw2DVs_);
if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) {
draw2DFsDepth_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsDepthCode, strlen(fsDepthCode), "draw2d_depth_fs");
_assert_(draw2DFsDepth_);
} else {
draw2DFsDepth_ = nullptr;
}
InputLayoutDesc desc = {
{
{ 16, false },
@@ -88,24 +106,46 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver
InputLayout *inputLayout = draw_->CreateInputLayout(desc);
BlendState *blendOff = draw_->CreateBlendState({ false, 0xF });
DepthStencilStateDesc dsDesc{};
DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(dsDesc);
BlendState *blendDiscard = draw_->CreateBlendState({ false, 0x0 });
DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(DepthStencilStateDesc{});
RasterState *rasterNoCull = draw_->CreateRasterState({});
PipelineDesc stencilWriteDesc{
DepthStencilStateDesc dsWriteDesc{};
dsWriteDesc.depthTestEnabled = true;
dsWriteDesc.depthWriteEnabled = true;
dsWriteDesc.depthCompare = Draw::Comparison::ALWAYS;
DepthStencilState *depthWriteAlways = draw_->CreateDepthStencilState(dsWriteDesc);
PipelineDesc draw2DColorPipelineDesc{
Primitive::TRIANGLE_STRIP,
{ draw2DVs_, draw2DFs_ },
inputLayout, noDepthStencil, blendOff, rasterNoCull, nullptr,
};
draw2DPipelineLinear_ = draw_->CreateGraphicsPipeline(stencilWriteDesc);
_assert_(draw2DPipelineLinear_);
draw2DPipelineColor_ = draw_->CreateGraphicsPipeline(draw2DColorPipelineDesc);
PipelineDesc draw2DDepthPipelineDesc{
Primitive::TRIANGLE_STRIP,
{ draw2DVs_, draw2DFsDepth_ },
inputLayout, depthWriteAlways, blendDiscard, rasterNoCull, nullptr,
};
if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) {
draw2DPipelineDepth_ = draw_->CreateGraphicsPipeline(draw2DDepthPipelineDesc);
_assert_(draw2DPipelineDepth_);
} else {
draw2DPipelineDepth_ = nullptr;
}
delete[] fsCode;
delete[] vsCode;
rasterNoCull->Release();
blendOff->Release();
blendDiscard->Release();
noDepthStencil->Release();
depthWriteAlways->Release();
inputLayout->Release();
SamplerStateDesc descLinear{};
@@ -125,7 +165,11 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver
draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest);
}
draw_->BindPipeline(draw2DPipelineLinear_);
if (channel == RASTER_DEPTH && !draw2DPipelineDepth_) {
return;
}
draw_->BindPipeline(channel == RASTER_COLOR ? draw2DPipelineColor_ : draw2DPipelineDepth_);
if (tex) {
draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex);
}
+54 -20
View File
@@ -283,7 +283,7 @@ 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);
}
FramebufferRenderMode mode = FB_MODE_NORMAL;
RasterMode mode = RASTER_MODE_NORMAL;
// Find a matching framebuffer
VirtualFramebuffer *vfb = nullptr;
@@ -331,7 +331,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
// 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 = FB_MODE_COLOR_TO_DEPTH;
mode = RASTER_MODE_COLOR_TO_DEPTH;
break;
}
} else if (v->fb_stride == params.fb_stride && v->format == params.fmt) {
@@ -368,7 +368,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
}
}
if (mode == FB_MODE_COLOR_TO_DEPTH) {
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.
//
@@ -564,6 +564,8 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
_dbg_assert_(src && dst);
_dbg_assert_(src != dst);
// Check that the depth address is even the same before actually blitting.
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
bool matchingSize = (src->width == dst->width || (src->width == 512 && dst->width == 480) || (src->width == 480 && dst->width == 512)) && src->height == dst->height;
@@ -579,7 +581,20 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
return;
}
gpuStats.numDepthCopies++;
bool useCopy = draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported);
bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported;
bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported;
// Could do an attempt at optimization - if destination already bound, draw depth using raster.
// Let's experiment later, commented out for now. Currently we fall back to raster as a last resort here.
/*
if (currentRenderVfb_ == dst) {
useCopy = false;
useBlit = false;
}
*/
int w = std::min(src->renderWidth, dst->renderWidth);
int h = std::min(src->renderHeight, dst->renderHeight);
@@ -587,14 +602,20 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
// TODO: It might even be advantageous on some GPUs to do this copy using a fragment shader that writes to Z, that way upcoming commands can just continue that render pass.
// Some GPUs can copy depth but only if stencil gets to come along for the ride. We only want to use this if there is no blit functionality.
if (draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported)) {
if (useCopy) {
draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth");
RebindFramebuffer("After BlitFramebufferDepth");
} else if (draw_->GetDeviceCaps().framebufferDepthBlitSupported) {
} else if (useBlit) {
// We'll accept whether we get a separate depth blit or not...
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);
}
draw_->InvalidateCachedState();
gpuStats.numDepthCopies++;
dst->last_frame_depth_updated = gpuStats.numFlips;
}
@@ -2495,11 +2516,13 @@ void FramebufferManagerCommon::DeviceLost() {
DoRelease(stencilUploadVs_);
DoRelease(stencilUploadSampler_);
DoRelease(stencilUploadPipeline_);
DoRelease(draw2DPipelineLinear_);
DoRelease(draw2DPipelineColor_);
DoRelease(draw2DPipelineDepth_);
DoRelease(draw2DSamplerNearest_);
DoRelease(draw2DSamplerLinear_);
DoRelease(draw2DVs_);
DoRelease(draw2DFs_);
DoRelease(draw2DFsDepth_);
presentation_->DeviceLost();
draw_ = nullptr;
}
@@ -2557,15 +2580,18 @@ 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);
DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0, RASTER_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);
}
void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) {
RasterChannel channel = RASTER_COLOR;
if (!dst->fbo || !src->fbo || !useBufferedRendering_) {
// This can happen if they recently switched from non-buffered.
if (useBufferedRendering_) {
// Just bind the back buffer for rendering, forget about doing anything else as we're in a weird state.
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer");
}
return;
@@ -2638,30 +2664,39 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX
const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2;
const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2;
if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) {
draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag);
draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1,
channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, tag);
return;
}
}
if (useBlit) {
draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag);
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 {
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);
BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, false, channel);
srcFBO = tempFBO;
}
BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false);
BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false, channel);
}
draw_->InvalidateCachedState();
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE);
}
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) {
bool linearFilter,
RasterChannel channel) {
if (channel == RASTER_DEPTH) {
_dbg_assert_(draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported);
}
int destW, destH, srcW, srcH;
draw_->GetFramebufferDimensions(src, &srcW, &srcH);
@@ -2678,17 +2713,16 @@ void FramebufferManagerCommon::BlitUsingRaster(
{ -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 },
};
if (dest != currentRenderVfb_->fbo) {
// 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);
draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitUsingRaster");
}
draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0);
// 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::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);
DrawStrip2D(nullptr, vtx, 4, linearFilter, channel);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
+6 -4
View File
@@ -359,7 +359,7 @@ 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);
void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel);
bool UpdateSize();
@@ -367,11 +367,11 @@ protected:
virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra
// Used by ReadFramebufferToMemory and later framebuffer block copies
virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag);
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag);
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);
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter, RasterChannel channel);
void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags);
@@ -485,9 +485,11 @@ protected:
Draw::SamplerState *stencilUploadSampler_ = nullptr;
// Draw2D pipelines
Draw::Pipeline *draw2DPipelineLinear_ = nullptr;
Draw::Pipeline *draw2DPipelineColor_ = nullptr;
Draw::Pipeline *draw2DPipelineDepth_ = nullptr;
Draw::SamplerState *draw2DSamplerLinear_ = nullptr;
Draw::SamplerState *draw2DSamplerNearest_ = nullptr;
Draw::ShaderModule *draw2DVs_ = nullptr;
Draw::ShaderModule *draw2DFs_ = nullptr;
Draw::ShaderModule *draw2DFsDepth_ = nullptr;
};
+1 -1
View File
@@ -1018,7 +1018,7 @@ void ConvertMaskState(GenericMaskState &maskState, bool allowFramebufferRead) {
return;
}
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
// Suppress color writes entirely in this mode.
maskState.applyFramebufferRead = false;
maskState.rgba[0] = false;
+2 -2
View File
@@ -28,7 +28,7 @@ bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBuff
writer.DeclareSamplers(samplers);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings, FSFLAG_NONE);
writer.C(" vec4 val = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n");
@@ -68,7 +68,7 @@ bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBuff
break;
}
writer.EndFSMain("outColor");
writer.EndFSMain("outColor", FSFLAG_NONE);
return true;
}
+1 -1
View File
@@ -264,7 +264,7 @@ 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 == FramebufferRenderMode::FB_MODE_COLOR_TO_DEPTH;
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.
+2 -2
View File
@@ -94,7 +94,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw:
writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n");
writer.BeginFSMain(uniforms, varyings);
writer.BeginFSMain(uniforms, varyings, FSFLAG_NONE);
writer.C(" vec4 index = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n");
writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a.
@@ -106,7 +106,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw:
writer.C(" gl_FragDepth = gl_FragCoord.z;\n");
}
writer.EndFSMain("outColor");
writer.EndFSMain("outColor", FSFLAG_NONE);
}
// This can probably be shared with some other shaders, like reinterpret or the future depth upload.
+19 -19
View File
@@ -265,7 +265,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac
}
}
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
forceFiltering = TEX_FILTER_FORCE_NEAREST;
}
@@ -625,8 +625,8 @@ std::vector<AttachCandidate> TextureCacheCommon::GetFramebufferCandidates(const
std::vector<AttachCandidate> candidates;
FramebufferNotificationChannel channel = Memory::IsDepthTexVRAMAddress(entry.addr) ? FramebufferNotificationChannel::NOTIFY_FB_DEPTH : FramebufferNotificationChannel::NOTIFY_FB_COLOR;
if (channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) {
RasterChannel channel = Memory::IsDepthTexVRAMAddress(entry.addr) ? RasterChannel::RASTER_DEPTH : RasterChannel::RASTER_COLOR;
if (channel == RasterChannel::RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) {
// Depth texture not supported. Don't try to match it, fall back to the memory behind..
return std::vector<AttachCandidate>();
}
@@ -645,7 +645,7 @@ std::vector<AttachCandidate> TextureCacheCommon::GetFramebufferCandidates(const
}
if (candidates.size() > 1) {
bool depth = channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH;
bool depth = channel == RasterChannel::RASTER_DEPTH;
std::string cands;
for (auto &candidate : candidates) {
@@ -687,7 +687,7 @@ int TextureCacheCommon::GetBestCandidateIndex(const std::vector<AttachCandidate>
}
// Bonus point for matching stride.
if (candidate.channel == NOTIFY_FB_COLOR && candidate.fb->fb_stride == candidate.entry.bufw) {
if (candidate.channel == RASTER_COLOR && candidate.fb->fb_stride == candidate.entry.bufw) {
relevancy += 100;
}
@@ -696,9 +696,9 @@ int TextureCacheCommon::GetBestCandidateIndex(const std::vector<AttachCandidate>
relevancy += 10;
}
if (candidate.channel == NOTIFY_FB_COLOR && candidate.fb->last_frame_render == gpuStats.numFlips) {
if (candidate.channel == RASTER_COLOR && candidate.fb->last_frame_render == gpuStats.numFlips) {
relevancy += 5;
} else if (candidate.channel == NOTIFY_FB_DEPTH && candidate.fb->last_frame_depth_render == gpuStats.numFlips) {
} else if (candidate.channel == RASTER_DEPTH && candidate.fb->last_frame_depth_render == gpuStats.numFlips) {
relevancy += 5;
}
@@ -878,10 +878,10 @@ void TextureCacheCommon::NotifyFramebuffer(VirtualFramebuffer *framebuffer, Fram
FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer(
const TextureDefinition &entry,
VirtualFramebuffer *framebuffer, u32 texaddrOffset, FramebufferNotificationChannel channel) const {
VirtualFramebuffer *framebuffer, u32 texaddrOffset, RasterChannel channel) const {
static const u32 MAX_SUBAREA_Y_OFFSET_SAFE = 32;
uint32_t fb_address = channel == NOTIFY_FB_DEPTH ? framebuffer->z_address : framebuffer->fb_address;
uint32_t fb_address = channel == RASTER_DEPTH ? framebuffer->z_address : framebuffer->fb_address;
u32 addr = fb_address & 0x3FFFFFFF;
u32 texaddr = entry.addr + texaddrOffset;
@@ -906,14 +906,14 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer(
case 0x00000000:
case 0x00400000:
// Don't match the depth channel with these addresses when texturing.
if (channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH) {
if (channel == RasterChannel::RASTER_DEPTH) {
return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH };
}
break;
case 0x00200000:
case 0x00600000:
// Don't match the color channel with these addresses when texturing.
if (channel == FramebufferNotificationChannel::NOTIFY_FB_COLOR) {
if (channel == RasterChannel::RASTER_COLOR) {
return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH };
}
break;
@@ -924,7 +924,7 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer(
}
const bool noOffset = texaddr == addr;
const bool exactMatch = noOffset && entry.format < 4 && channel == NOTIFY_FB_COLOR;
const bool exactMatch = noOffset && entry.format < 4 && channel == RASTER_COLOR;
const u32 w = 1 << ((entry.dim >> 0) & 0xf);
const u32 h = 1 << ((entry.dim >> 8) & 0xf);
// 512 on a 272 framebuffer is sane, so let's be lenient.
@@ -958,9 +958,9 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer(
// Check works for D16 too (???)
const bool matchingClutFormat =
(channel != NOTIFY_FB_COLOR && entry.format == GE_TFMT_CLUT16) ||
(channel == NOTIFY_FB_COLOR && framebuffer->format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) ||
(channel == NOTIFY_FB_COLOR && framebuffer->format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16);
(channel != RASTER_COLOR && entry.format == GE_TFMT_CLUT16) ||
(channel == RASTER_COLOR && framebuffer->format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) ||
(channel == RASTER_COLOR && framebuffer->format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16);
// To avoid ruining git blame, kept the same name as the old struct.
FramebufferMatchInfo fbInfo{ FramebufferMatch::VALID };
@@ -1782,7 +1782,7 @@ void TextureCacheCommon::ApplyTexture() {
if (nextFramebufferTexture_) {
bool depth = Memory::IsDepthTexVRAMAddress(gstate.getTextureAddress(0));
// ApplyTextureFrameBuffer is responsible for setting SetTextureFullAlpha.
ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), depth ? NOTIFY_FB_DEPTH : NOTIFY_FB_COLOR);
ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), depth ? RASTER_DEPTH : RASTER_COLOR);
nextFramebufferTexture_ = nullptr;
}
@@ -1845,12 +1845,12 @@ void TextureCacheCommon::ApplyTexture() {
gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0);
}
void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) {
void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel) {
DepalShader *depalShader = nullptr;
uint32_t clutMode = gstate.clutformat & 0xFFFFFF;
bool need_depalettize = IsClutFormat(texFormat);
bool depth = channel == NOTIFY_FB_DEPTH;
bool depth = channel == RASTER_DEPTH;
bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && !depth && !gstate_c.curTextureIs3D;
// TODO: Implement shader depal in the fragment shader generator for D3D11 at least.
@@ -2262,7 +2262,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
}
// Don't upscale textures in color-to-depth mode.
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
plan.scaleFactor = 1;
}
+4 -8
View File
@@ -25,6 +25,7 @@
#include "Common/MemoryUtil.h"
#include "Core/TextureReplacer.h"
#include "Core/System.h"
#include "GPU/GPU.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/TextureScalerCommon.h"
@@ -36,11 +37,6 @@ enum FramebufferNotification {
NOTIFY_FB_DESTROYED,
};
enum FramebufferNotificationChannel {
NOTIFY_FB_COLOR = 0,
NOTIFY_FB_DEPTH = 1,
};
// Changes more frequent than this will be considered "frequent" and prevent texture scaling.
#define TEXCACHE_FRAME_CHANGE_FREQUENT 6
// Note: only used when hash backoff is disabled.
@@ -229,7 +225,7 @@ struct AttachCandidate {
FramebufferMatchInfo match;
TextureDefinition entry;
VirtualFramebuffer *fb;
FramebufferNotificationChannel channel;
RasterChannel channel;
std::string ToString();
};
@@ -336,7 +332,7 @@ protected:
void DeleteTexture(TexCache::iterator it);
void Decimate(bool forcePressure = false);
void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel);
void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel);
void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete);
virtual void BuildTexture(TexCacheEntry *const entry) = 0;
@@ -369,7 +365,7 @@ protected:
SamplerCacheKey GetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight);
void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode);
FramebufferMatchInfo MatchFramebuffer(const TextureDefinition &entry, VirtualFramebuffer *framebuffer, u32 texaddrOffset, FramebufferNotificationChannel channel) const;
FramebufferMatchInfo MatchFramebuffer(const TextureDefinition &entry, VirtualFramebuffer *framebuffer, u32 texaddrOffset, RasterChannel channel) const;
std::vector<AttachCandidate> GetFramebufferCandidates(const TextureDefinition &entry, u32 texAddrOffset);
int GetBestCandidateIndex(const std::vector<AttachCandidate> &candidates);
+1 -1
View File
@@ -293,7 +293,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
GenericStencilFuncState stencilState;
ConvertStencilFuncState(stencilState);
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
// Enforce plain depth writing.
keys_.depthStencil.value = 0;
keys_.depthStencil.depthTestEnable = true;
+1 -1
View File
@@ -214,7 +214,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
// Set Stencil/Depth
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
// Enforce plain depth writing.
dxstate.depthTest.enable();
dxstate.depthFunc.set(D3DCMP_ALWAYS);
+1 -1
View File
@@ -251,7 +251,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
GenericStencilFuncState stencilState;
ConvertStencilFuncState(stencilState);
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
// Enforce plain depth writing.
renderManager->SetStencilDisabled();
renderManager->SetDepth(true, true, GL_ALWAYS);
+11 -3
View File
@@ -24,9 +24,17 @@ class GPUInterface;
class GPUDebugInterface;
class GraphicsContext;
enum FramebufferRenderMode {
FB_MODE_NORMAL = 0,
FB_MODE_COLOR_TO_DEPTH = 1,
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.
enum RasterChannel {
RASTER_COLOR = 0,
RASTER_DEPTH = 1,
};
enum SkipDrawReasonFlags {
+2 -2
View File
@@ -555,7 +555,7 @@ struct GPUStateCache {
Dirty(DIRTY_FRAGMENTSHADER_STATE | (is3D ? DIRTY_MIPBIAS : 0));
}
}
void SetFramebufferRenderMode(FramebufferRenderMode mode) {
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.
@@ -614,7 +614,7 @@ struct GPUStateCache {
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.
FramebufferRenderMode renderMode;
RasterMode renderMode;
// TODO: These should be accessed from the current VFB object directly.
u32 curRTWidth;
+1 -1
View File
@@ -250,7 +250,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
GenericStencilFuncState stencilState;
ConvertStencilFuncState(stencilState);
if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) {
if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) {
// Enforce plain depth writing.
key.depthTestEnable = true;
key.depthWriteEnable = true;