mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 17:19:28 +01:00
Merge pull request #22887 from hrydgard/fix-stencil-rebuild-cost
Reinterpret: Write the stencil from the source, in the same render pass
This commit is contained in:
8 files changed
+157
-57
No files matched your search
+23
-9
@@ -42,11 +42,17 @@ const UniformDef g_draw2Duniforms[2] = {
|
||||
{ "float", "scaleFactor", 1},
|
||||
};
|
||||
|
||||
const UniformDef g_draw2DStencilUniforms[3] = {
|
||||
{ "vec2", "texSize", 0 },
|
||||
{ "float", "scaleFactor", 1},
|
||||
{ "float", "stencilValue", 2},
|
||||
};
|
||||
|
||||
struct Draw2DUB {
|
||||
float texSizeX;
|
||||
float texSizeY;
|
||||
float scaleFactor;
|
||||
float zScale;
|
||||
float stencilValue;
|
||||
float zScaleInv;
|
||||
float zOffset;
|
||||
};
|
||||
@@ -54,6 +60,7 @@ struct Draw2DUB {
|
||||
const UniformBufferDesc draw2DUBDesc{ sizeof(Draw2DUB), {
|
||||
{ "texSize", -1, 0, UniformType::FLOAT2, 0 },
|
||||
{ "scaleFactor", -1, 1, UniformType::FLOAT1, 8 },
|
||||
{ "stencilValue", -1, 2, UniformType::FLOAT1, 12 },
|
||||
} };
|
||||
|
||||
Draw2DPipelineInfo GenerateDraw2DCopyColorFs(ShaderWriter &writer) {
|
||||
@@ -253,7 +260,7 @@ void Draw2D::Ensure2DResources() {
|
||||
}
|
||||
}
|
||||
|
||||
Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (ShaderWriter &)> generate) {
|
||||
Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (ShaderWriter &)> generate, Slice<const char *> extensions) {
|
||||
Ensure2DResources();
|
||||
|
||||
using namespace Draw;
|
||||
@@ -264,7 +271,7 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (Shade
|
||||
if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
|
||||
flags = ShaderWriterFlags::FS_AUTO_STEREO;
|
||||
}
|
||||
ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment, Slice<const char *>::empty(), flags);
|
||||
ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment, extensions, flags);
|
||||
Draw2DPipelineInfo info = generate(writer);
|
||||
_assert_msg_(strlen(fsCode) < 8192, "Draw2D FS length error: %d", (int)strlen(fsCode));
|
||||
|
||||
@@ -282,10 +289,16 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (Shade
|
||||
};
|
||||
InputLayout *inputLayout = draw_->CreateInputLayout(desc);
|
||||
|
||||
BlendState *blend = draw_->CreateBlendState({ false, info.writeChannel == RASTER_COLOR ? 0xF : 0x0 });
|
||||
BlendState *blend = draw_->CreateBlendState({ false, (info.writeChannel == RASTER_COLOR && !info.writeStencil) ? 0xF : 0x0 });
|
||||
|
||||
DepthStencilStateDesc dsDesc{};
|
||||
if (info.writeChannel == RASTER_DEPTH) {
|
||||
if (info.writeStencil) {
|
||||
dsDesc.stencilEnabled = true;
|
||||
dsDesc.stencil.compareOp = Comparison::ALWAYS;
|
||||
dsDesc.stencil.failOp = StencilOp::REPLACE;
|
||||
dsDesc.stencil.passOp = StencilOp::REPLACE;
|
||||
dsDesc.stencil.depthFailOp = StencilOp::REPLACE;
|
||||
} else if (info.writeChannel == RASTER_DEPTH) {
|
||||
dsDesc.depthTestEnabled = true;
|
||||
dsDesc.depthWriteEnabled = true;
|
||||
dsDesc.depthCompare = Draw::Comparison::ALWAYS;
|
||||
@@ -321,7 +334,7 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (Shade
|
||||
};
|
||||
}
|
||||
|
||||
void Draw2D::Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2, float srcWidth, float srcHeight, float dstWidth, float dstHeight, bool linear, int scaleFactor) {
|
||||
void Draw2D::Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2, float srcWidth, float srcHeight, float dstWidth, float dstHeight, bool linear, int scaleFactor, float stencilValue) {
|
||||
float dX = 1.0f / (float)dstWidth;
|
||||
float dY = 1.0f / (float)dstHeight;
|
||||
float sX = 1.0f / (float)srcWidth;
|
||||
@@ -339,10 +352,10 @@ void Draw2D::Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX
|
||||
{ -1.0f + 2.0f * dX * dstX2 + xOffset, -(1.0f - 2.0f * dY * dstY2) + yOffset, sX * srcX2, sY * srcY2 },
|
||||
};
|
||||
|
||||
DrawStrip2D(nullptr, vtx, 4, linear, pipeline, srcWidth, srcHeight, scaleFactor);
|
||||
DrawStrip2D(nullptr, vtx, 4, linear, pipeline, srcWidth, srcHeight, scaleFactor, stencilValue);
|
||||
}
|
||||
|
||||
void Draw2D::DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW, float texH, int scaleFactor) {
|
||||
void Draw2D::DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW, float texH, int scaleFactor, float stencilValue) {
|
||||
using namespace Draw;
|
||||
|
||||
_dbg_assert_(pipeline);
|
||||
@@ -354,10 +367,11 @@ void Draw2D::DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vert
|
||||
linearFilter = false;
|
||||
}
|
||||
|
||||
Draw2DUB ub;
|
||||
Draw2DUB ub{};
|
||||
ub.texSizeX = tex ? tex->Width() : texW;
|
||||
ub.texSizeY = tex ? tex->Height() : texH;
|
||||
ub.scaleFactor = (float)scaleFactor;
|
||||
ub.stencilValue = stencilValue;
|
||||
|
||||
draw_->BindPipeline(pipeline->pipeline);
|
||||
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
|
||||
|
||||
+7
-3
@@ -42,9 +42,13 @@ struct Draw2DPipelineInfo {
|
||||
RasterChannel writeChannel;
|
||||
Slice<SamplerDef> samplers;
|
||||
bool readSamples = false; // Binds the source with BindFramebufferSamplesAsTexture.
|
||||
// Writes only the stencil, with REPLACE: the reference from SetStencilParams, or exported by the shader.
|
||||
bool writeStencil = false;
|
||||
};
|
||||
|
||||
extern const UniformDef g_draw2Duniforms[2];
|
||||
// g_draw2Duniforms plus stencilValue, for writeStencil pipelines.
|
||||
extern const UniformDef g_draw2DStencilUniforms[3];
|
||||
|
||||
struct Draw2DPipeline {
|
||||
Draw::Pipeline *pipeline;
|
||||
@@ -67,11 +71,11 @@ public:
|
||||
void DeviceLost();
|
||||
void DeviceRestore(Draw::DrawContext *draw);
|
||||
|
||||
Draw2DPipeline *Create2DPipeline(std::function<Draw2DPipelineInfo(ShaderWriter &)> generate);
|
||||
Draw2DPipeline *Create2DPipeline(std::function<Draw2DPipelineInfo(ShaderWriter &)> generate, Slice<const char *> extensions = Slice<const char *>::empty());
|
||||
|
||||
void DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW = 0.0f, float texH = 0.0f, int scaleFactor = 0);
|
||||
void DrawStrip2D(Draw::Texture *tex, const Draw2DVertex *verts, int vertexCount, bool linearFilter, Draw2DPipeline *pipeline, float texW = 0.0f, float texH = 0.0f, int scaleFactor = 0, float stencilValue = 0.0f);
|
||||
|
||||
void Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2, float srcWidth, float srcHeight, float dstWidth, float dstHeight, bool linear, int scaleFactor);
|
||||
void Blit(Draw2DPipeline *pipeline, float srcX1, float srcY1, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2, float srcWidth, float srcHeight, float dstWidth, float dstHeight, bool linear, int scaleFactor, float stencilValue = 0.0f);
|
||||
void Ensure2DResources();
|
||||
|
||||
private:
|
||||
|
||||
@@ -942,16 +942,16 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra
|
||||
// OK we have the pipeline, now just do the blit.
|
||||
BlitUsingRaster(src->fbo, 0.0f, 0.0f, srcWidth, srcHeight,
|
||||
dst->fbo, dstX1, dstY1, dstX2, dstY2, false, dst->renderScaleFactor, pipeline, pass_name);
|
||||
if (src->fb_format != dst->fb_format) {
|
||||
// In the same render pass.
|
||||
WriteStencilFromReinterpret(src, dst, srcWidth, srcHeight, dstX1, dstY1, dstX2, dstY2);
|
||||
}
|
||||
}
|
||||
|
||||
if (scaleFactorX == 1.0f && dst->z_address == src->z_address && dst->z_stride == src->z_stride) {
|
||||
// We should also copy the depth buffer in this case!
|
||||
BlitFramebufferDepth(src, dst, true);
|
||||
}
|
||||
|
||||
if (pipeline && src->fb_format != dst->fb_format) {
|
||||
WriteStencilFromFramebufferAlpha(dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -993,6 +993,22 @@ Draw2DPipeline *FramebufferManagerCommon::GetReinterpretPipeline(GEBufferFormat
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
Draw2DPipeline *FramebufferManagerCommon::GetReinterpretStencilPipeline(GEBufferFormat from, GEBufferFormat to, bool useExport) {
|
||||
// Which variant is decided by the device, so it doesn't change.
|
||||
Draw2DPipeline *pipeline = reinterpretStencilFromTo_[(int)from][(int)to];
|
||||
if (!pipeline) {
|
||||
const Draw::Bugs &bugs = draw_->GetBugs();
|
||||
const bool discardNeedsDepthWrite = bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI) || bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO);
|
||||
const ReinterpretOutput output = useExport ? ReinterpretOutput::STENCIL_EXPORT : ReinterpretOutput::STENCIL_BITS;
|
||||
static const char *const exportExtensions[1] = { g_stencilExportExtension };
|
||||
pipeline = draw2D_.Create2DPipeline([from, to, output, discardNeedsDepthWrite](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo {
|
||||
return GenerateReinterpretFragmentShader(shaderWriter, from, to, output, discardNeedsDepthWrite);
|
||||
}, useExport ? Slice<const char *>(exportExtensions) : Slice<const char *>::empty());
|
||||
reinterpretStencilFromTo_[(int)from][(int)to] = pipeline;
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
|
||||
// Notify the texture cache of both the color and depth buffers.
|
||||
textureCache_->NotifyFramebuffer(v, NOTIFY_FB_DESTROYED);
|
||||
@@ -3785,6 +3801,7 @@ void FramebufferManagerCommon::ReleasePipelines() {
|
||||
for (int i = 0; i < ARRAY_SIZE(reinterpretFromTo_); i++) {
|
||||
for (int j = 0; j < ARRAY_SIZE(reinterpretFromTo_); j++) {
|
||||
DoRelease(reinterpretFromTo_[i][j]);
|
||||
DoRelease(reinterpretStencilFromTo_[i][j]);
|
||||
}
|
||||
}
|
||||
DoRelease(stencilWriteSampler_);
|
||||
|
||||
@@ -362,7 +362,7 @@ public:
|
||||
void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);
|
||||
bool PerformWriteStencilFromMemory(u32 addr, int size, WriteStencil flags);
|
||||
bool ReadbackStencilToMemory(u32 addr, int size);
|
||||
void WriteStencilFromFramebufferAlpha(VirtualFramebuffer *dst);
|
||||
void WriteStencilFromReinterpret(VirtualFramebuffer *src, VirtualFramebuffer *dst, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2);
|
||||
|
||||
// We changed our depth mode, gotta start over.
|
||||
// Ideally, we should convert depth buffers here, not just clear them.
|
||||
@@ -504,6 +504,7 @@ public:
|
||||
|
||||
// If from==to, returns a copy pipeline.
|
||||
Draw2DPipeline *GetReinterpretPipeline(GEBufferFormat from, GEBufferFormat to, float *scaleFactorX);
|
||||
Draw2DPipeline *GetReinterpretStencilPipeline(GEBufferFormat from, GEBufferFormat to, bool useExport);
|
||||
|
||||
// Public to be used from the texture cache's depal shenanigans.
|
||||
void BlitUsingRaster(
|
||||
@@ -688,6 +689,7 @@ protected:
|
||||
// Safe, not optimal - there might be input attachment tricks, etc, but we can't use them
|
||||
// since we don't want N different implementations.
|
||||
Draw2DPipeline *reinterpretFromTo_[4][4]{};
|
||||
Draw2DPipeline *reinterpretStencilFromTo_[4][4]{};
|
||||
|
||||
// Common implementation of stencil buffer upload. Also not 100% optimal, but not performance
|
||||
// critical either.
|
||||
|
||||
@@ -14,12 +14,20 @@ static const SamplerDef samplers[1] = {
|
||||
{ 0, "tex", SamplerFlags::ARRAY_ON_VULKAN }
|
||||
};
|
||||
|
||||
const char *const g_stencilExportExtension = "#extension GL_ARB_shader_stencil_export : require";
|
||||
|
||||
// Requires full size integer math. It would be possible to make a floating point-only version with lots of
|
||||
// modulo and stuff, might do it one day.
|
||||
Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to) {
|
||||
Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to, ReinterpretOutput output, bool discardNeedsDepthWrite) {
|
||||
const bool stencil = output != ReinterpretOutput::COLOR;
|
||||
|
||||
writer.HighPrecisionFloat();
|
||||
writer.DeclareSamplers(samplers);
|
||||
|
||||
if (output == ReinterpretOutput::STENCIL_BITS && discardNeedsDepthWrite) {
|
||||
writer.C("layout (depth_unchanged) out float gl_FragDepth;\n");
|
||||
}
|
||||
|
||||
if (writer.Lang().bitwiseOps) {
|
||||
switch (from) {
|
||||
case GE_FORMAT_4444:
|
||||
@@ -157,7 +165,11 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf
|
||||
}
|
||||
}
|
||||
|
||||
writer.BeginFSMain(g_draw2Duniforms, varyings);
|
||||
if (stencil) {
|
||||
writer.BeginFSMain(g_draw2DStencilUniforms, varyings);
|
||||
} else {
|
||||
writer.BeginFSMain(g_draw2Duniforms, varyings);
|
||||
}
|
||||
|
||||
if (IsBufferFormat16Bit(from) && IsBufferFormat16Bit(to)) {
|
||||
writer.C(" vec4 val = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n");
|
||||
@@ -189,12 +201,30 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf
|
||||
writer.C(" vec4 outColor = unpackColor(u == 0.0 ? packColor(val.rg) : packColor(val.ba));\n");
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
// The same rounding as the stencil upload shader.
|
||||
writer.C(" float alpha = floor(outColor.a * 255.99);\n");
|
||||
if (output == ReinterpretOutput::STENCIL_EXPORT) {
|
||||
writer.C(" gl_FragStencilRefARB = int(alpha);\n");
|
||||
} else {
|
||||
writer.C(" if (stencilValue > 0.0) {\n");
|
||||
writer.C(" float shifted = alpha / floor(stencilValue * 255.99);\n");
|
||||
writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n");
|
||||
writer.C(" }\n");
|
||||
if (discardNeedsDepthWrite) {
|
||||
writer.C(" gl_FragDepth = gl_FragCoord.z;\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.EndFSMain("outColor");
|
||||
|
||||
return Draw2DPipelineInfo{
|
||||
"reinterpret",
|
||||
Draw2DPipelineInfo info{
|
||||
stencil ? "reinterpret_stencil" : "reinterpret",
|
||||
RASTER_COLOR,
|
||||
RASTER_COLOR,
|
||||
};
|
||||
info.writeStencil = stencil;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -4,4 +4,16 @@
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/Common/Draw2D.h"
|
||||
|
||||
Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to);
|
||||
enum class ReinterpretOutput {
|
||||
COLOR,
|
||||
// The stencil from the reinterpreted alpha (the PSP's stencil is the alpha bits). The bit to write is in
|
||||
// stencilValue (as in the stencil upload shader), and 0 writes everywhere, to clear.
|
||||
STENCIL_BITS,
|
||||
// The whole stencil in one draw, through GL_ARB_shader_stencil_export.
|
||||
STENCIL_EXPORT,
|
||||
};
|
||||
|
||||
// The extension the writer needs for STENCIL_EXPORT.
|
||||
extern const char *const g_stencilExportExtension;
|
||||
|
||||
Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBufferFormat from, GEBufferFormat to, ReinterpretOutput output = ReinterpretOutput::COLOR, bool discardNeedsDepthWrite = false);
|
||||
@@ -264,8 +264,10 @@ void FramebufferManagerCommon::DrawStencilWritePasses(GEBufferFormat format, int
|
||||
|
||||
// On the PSP the stencil is the alpha bits, so after reinterpreting the colors of another format into a buffer, its
|
||||
// stencil has to follow the new alpha (Ultimate Ghosts 'n Goblins sets 5551 alpha through a masked 565 blue write,
|
||||
// then stencil tests on it).
|
||||
void FramebufferManagerCommon::WriteStencilFromFramebufferAlpha(VirtualFramebuffer *dst) {
|
||||
// then stencil tests on it). Called right after the color reinterpret, with the same rectangles, so dst is still the
|
||||
// render target and the draws land in the same render pass. They read the alpha the same way from src, so dst needs
|
||||
// no copy.
|
||||
void FramebufferManagerCommon::WriteStencilFromReinterpret(VirtualFramebuffer *src, VirtualFramebuffer *dst, float srcX2, float srcY2, float dstX1, float dstY1, float dstX2, float dstY2) {
|
||||
using namespace Draw;
|
||||
|
||||
int values = 0;
|
||||
@@ -275,30 +277,42 @@ void FramebufferManagerCommon::WriteStencilFromFramebufferAlpha(VirtualFramebuff
|
||||
case GE_FORMAT_8888: values = 256; break;
|
||||
default: return;
|
||||
}
|
||||
if (!dst->fbo) {
|
||||
if (!src->fbo || !dst->fbo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool useExportShader = draw_->GetDeviceCaps().fragmentShaderStencilWriteSupported;
|
||||
EnsureStencilWritePipeline(useExportShader);
|
||||
const bool useExport = draw_->GetDeviceCaps().fragmentShaderStencilWriteSupported;
|
||||
Draw2DPipeline *pipeline = GetReinterpretStencilPipeline(src->fb_format, dst->fb_format, useExport);
|
||||
|
||||
// The source can't be the target, so read the alpha from a copy.
|
||||
const int w = dst->renderWidth;
|
||||
const int h = dst->renderHeight;
|
||||
Framebuffer *copy = GetTempFBO(TempFBO::COPY, w, h);
|
||||
BlitUsingRaster(dst->fbo, 0.0f, 0.0f, (float)w, (float)h, copy, 0.0f, 0.0f, (float)w, (float)h, false, dst->renderScaleFactor, Get2DPipeline(DRAW2D_COPY_COLOR), "StencilFromAlpha_Copy");
|
||||
int srcW, srcH, dstW, dstH;
|
||||
draw_->GetFramebufferDimensions(src->fbo, &srcW, &srcH);
|
||||
draw_->GetFramebufferDimensions(dst->fbo, &dstW, &dstH);
|
||||
draw_->BindFramebufferAsTexture(src->fbo, 0, Aspect::COLOR_BIT, ALL_LAYERS);
|
||||
|
||||
draw_->BindFramebufferAsRenderTarget(dst->fbo, { RPAction::KEEP, RPAction::KEEP, RPAction::CLEAR }, "StencilFromAlpha");
|
||||
Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f };
|
||||
draw_->SetViewport(viewport);
|
||||
draw_->SetScissorRect(0, 0, w, h);
|
||||
draw_->BindFramebufferAsTexture(copy, TEX_SLOT_PSP_TEXTURE, Aspect::COLOR_BIT, 0);
|
||||
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilWriteSampler_);
|
||||
draw_->BindPipeline(stencilWritePipeline_);
|
||||
DrawStencilWritePasses(dst->fb_format, values, 0xFF, useExportShader);
|
||||
auto drawStencil = [&](uint8_t ref, uint8_t writeMask, float stencilValue) {
|
||||
// Vulkan only applies the stencil params to a bound pipeline that uses stencil.
|
||||
draw_->BindPipeline(pipeline->pipeline);
|
||||
draw_->SetStencilParams(ref, writeMask, 0xFF);
|
||||
draw2D_.Blit(pipeline, 0.0f, 0.0f, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, (float)srcW, (float)srcH, (float)dstW, (float)dstH, false, dst->renderScaleFactor, stencilValue);
|
||||
};
|
||||
|
||||
if (useExport) {
|
||||
drawStencil(0xFF, 0xFF, 0.0f);
|
||||
} else {
|
||||
// A draw can only set one bit, so clear first, then set each bit where the alpha has it.
|
||||
drawStencil(0, 0xFF, 0.0f);
|
||||
for (int i = 1; i < values; i += i) {
|
||||
if (dst->fb_format == GE_FORMAT_4444) {
|
||||
drawStencil(0xFF, (i << 4) | i, i * (16.0f / 255.0f));
|
||||
} else if (dst->fb_format == GE_FORMAT_5551) {
|
||||
drawStencil(0xFF, 0xFF, i * (128.0f / 255.0f));
|
||||
} else {
|
||||
drawStencil(0xFF, i, i * (1.0f / 255.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textureCache_->ForgetLastTexture();
|
||||
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
|
||||
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,22 +199,29 @@ bool TestReinterpretShaders() {
|
||||
|
||||
std::string errorMessage;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (i == j)
|
||||
continue; // useless shader!
|
||||
ShaderWriter writer(buffer, desc, ShaderStage::Fragment);
|
||||
GenerateReinterpretFragmentShader(writer, fmts[i], fmts[j]);
|
||||
if (strlen(buffer) >= 8192) {
|
||||
printf("Reinterpret fragment shader %d exceeded buffer:\n\n%s\n", (int)j, LineNumberString(buffer).c_str());
|
||||
failed = true;
|
||||
}
|
||||
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
|
||||
printf("Error compiling reinterpret fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str());
|
||||
failed = true;
|
||||
} else {
|
||||
if (g_testLog) {
|
||||
printf("===\n%s\n===\n", buffer);
|
||||
// Stencil export only on Vulkan, as GLSL_3xx is ES, which doesn't support it.
|
||||
const int numOutputs = languages[k] == ShaderLanguage::GLSL_VULKAN ? 3 : 2;
|
||||
for (int o = 0; o < numOutputs; o++) {
|
||||
const ReinterpretOutput output = (ReinterpretOutput)o;
|
||||
const char *extensions[1] = { g_stencilExportExtension };
|
||||
const Slice<const char *> writerExtensions = output == ReinterpretOutput::STENCIL_EXPORT ? Slice<const char *>(extensions) : Slice<const char *>::empty();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (i == j)
|
||||
continue; // useless shader!
|
||||
ShaderWriter writer(buffer, desc, ShaderStage::Fragment, writerExtensions);
|
||||
GenerateReinterpretFragmentShader(writer, fmts[i], fmts[j], output);
|
||||
if (strlen(buffer) >= 8192) {
|
||||
printf("Reinterpret fragment shader %d (output %d) exceeded buffer:\n\n%s\n", (int)j, o, LineNumberString(buffer).c_str());
|
||||
failed = true;
|
||||
}
|
||||
if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) {
|
||||
printf("Error compiling reinterpret fragment shader %d (output %d):\n\n%s\n\n%s\n", (int)j, o, LineNumberString(buffer).c_str(), errorMessage.c_str());
|
||||
failed = true;
|
||||
} else {
|
||||
if (g_testLog) {
|
||||
printf("===\n%s\n===\n", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user