CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/Common/ShaderId.cpp
Views: 1401
#include <string>1#include <sstream>2#include <array>34#include "Common/GPU/thin3d.h"5#include "Common/StringUtils.h"6#include "Core/System.h"7#include "Core/Config.h"89#include "GPU/ge_constants.h"10#include "GPU/GPU.h"11#include "GPU/GPUState.h"12#include "GPU/Common/GPUStateUtils.h"13#include "GPU/Common/ShaderId.h"14#include "GPU/Common/VertexDecoderCommon.h"1516std::string VertexShaderDesc(const VShaderID &id) {17std::stringstream desc;18desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);19if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";20if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX ";21if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C ";22if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T ";23if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N ";24if (id.Bit(VS_BIT_LMODE)) desc << "LM ";25if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN ";26int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2);27if (uvgMode == GE_TEXMAP_TEXTURE_MATRIX) {28int uvprojMode = id.Bits(VS_BIT_UVPROJ_MODE, 2);29const char *uvprojModes[4] = { "TexProjPos ", "TexProjUV ", "TexProjNNrm ", "TexProjNrm " };30desc << uvprojModes[uvprojMode];31}32static constexpr std::array<const char*, 4> uvgModes = { "UV ", "UVMtx ", "UVEnv ", "UVUnk " };33int ls0 = id.Bits(VS_BIT_LS0, 2);34int ls1 = id.Bits(VS_BIT_LS1, 2);3536if (uvgMode) desc << uvgModes[uvgMode];37if (id.Bit(VS_BIT_ENABLE_BONES)) desc << "Bones:" << (id.Bits(VS_BIT_BONES, 3) + 1) << " ";38// Lights39if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {40desc << "Light: ";41}42if (id.Bit(VS_BIT_LIGHT_UBERSHADER)) {43desc << "LightUberShader ";44}45for (int i = 0; i < 4; i++) {46bool enabled = id.Bit(VS_BIT_LIGHT0_ENABLE + i) && id.Bit(VS_BIT_LIGHTING_ENABLE);47if (enabled || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {48desc << i << ": ";49desc << "c:" << id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2) << " t:" << id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2) << " ";50}51}52if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc << "MatUp:" << id.Bits(VS_BIT_MATERIAL_UPDATE, 3) << " ";53if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";54if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";5556if (id.Bit(VS_BIT_BEZIER)) desc << "Bezier ";57if (id.Bit(VS_BIT_SPLINE)) desc << "Spline ";58if (id.Bit(VS_BIT_HAS_COLOR_TESS)) desc << "TessC ";59if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT ";60if (id.Bit(VS_BIT_HAS_NORMAL_TESS)) desc << "TessN ";61if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN ";62if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "Cull ";6364if (id.Bit(VS_BIT_SIMPLE_STEREO)) desc << "SimpleStereo ";6566return desc.str();67}6869void ComputeVertexShaderID(VShaderID *id_out, VertexDecoder *vertexDecoder, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {70u32 vertType = vertexDecoder->VertexType();7172bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;73bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();74bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);75bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();7677bool vtypeHasColor = (vertType & GE_VTYPE_COL_MASK) != 0;78bool vtypeHasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;79bool vtypeHasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;8081bool doBezier = gstate_c.submitType == SubmitType::HW_BEZIER;82bool doSpline = gstate_c.submitType == SubmitType::HW_SPLINE;8384if (doBezier || doSpline) {85_assert_(vtypeHasNormal);86}8788bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough && !gstate.isModeClear();89bool vertexRangeCulling = gstate_c.Use(GPU_USE_VS_RANGE_CULLING) &&90!isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #116929192VShaderID id;93id.SetBit(VS_BIT_LMODE, lmode);94id.SetBit(VS_BIT_IS_THROUGH, isModeThrough);95id.SetBit(VS_BIT_HAS_COLOR, vtypeHasColor);96id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling);9798if (!isModeThrough && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {99id.SetBit(VS_BIT_SIMPLE_STEREO);100}101102if (doTexture) {103// UV generation mode. doShadeMapping is implicitly stored here.104id.SetBits(VS_BIT_UVGEN_MODE, 2, gstate.getUVGenMode());105}106107if (useHWTransform) {108id.SetBit(VS_BIT_USE_HW_TRANSFORM);109id.SetBit(VS_BIT_HAS_NORMAL, vtypeHasNormal);110111// The next bits are used differently depending on UVgen mode112if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX) {113id.SetBits(VS_BIT_UVPROJ_MODE, 2, gstate.getUVProjMode());114} else if (doShadeMapping) {115id.SetBits(VS_BIT_LS0, 2, gstate.getUVLS0());116id.SetBits(VS_BIT_LS1, 2, gstate.getUVLS1());117}118119// Bones.120u32 vertType = vertexDecoder->VertexType();121bool enableBones = !useSkinInDecode && vertTypeIsSkinningEnabled(vertType);122id.SetBit(VS_BIT_ENABLE_BONES, enableBones);123if (enableBones) {124id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);125// 2 bits. We should probably send in the weight scalefactor as a uniform instead,126// or simply preconvert all weights to floats.127id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, weightsAsFloat ? 0 : (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);128}129130if (gstate.isLightingEnabled()) {131// doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping.132id.SetBit(VS_BIT_LIGHTING_ENABLE);133if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {134id.SetBit(VS_BIT_LIGHT_UBERSHADER);135} else {136id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate());137// Light bits138for (int i = 0; i < 4; i++) {139bool chanEnabled = gstate.isLightChanEnabled(i) != 0;140id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);141if (chanEnabled) {142id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));143id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));144}145}146}147}148149id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());150id.SetBit(VS_BIT_HAS_TEXCOORD, vtypeHasTexcoord);151152if (useHWTessellation) {153id.SetBit(VS_BIT_BEZIER, doBezier);154id.SetBit(VS_BIT_SPLINE, doSpline);155if (doBezier || doSpline) {156// These are the original vertType's values (normalized will always have colors, etc.)157id.SetBit(VS_BIT_HAS_COLOR_TESS, (gstate.vertType & GE_VTYPE_COL_MASK) != 0);158id.SetBit(VS_BIT_HAS_TEXCOORD_TESS, (gstate.vertType & GE_VTYPE_TC_MASK) != 0);159id.SetBit(VS_BIT_HAS_NORMAL_TESS, (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 || gstate.isLightingEnabled());160}161id.SetBit(VS_BIT_NORM_REVERSE_TESS, gstate.isPatchNormalsReversed());162}163}164165id.SetBit(VS_BIT_FLATSHADE, doFlatShading);166167// These two bits cannot be combined, otherwise havoc occurs. We get reports that indicate this happened somehow... "ERROR: 0:14: 'u_proj' : undeclared identifier"168_dbg_assert_msg_(!id.Bit(VS_BIT_USE_HW_TRANSFORM) || !id.Bit(VS_BIT_IS_THROUGH), "Can't have both THROUGH and USE_HW_TRANSFORM together!");169170*id_out = id;171}172173174static const char * const alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };175static const char * const logicFuncs[] = {176"CLEAR", "AND", "AND_REV", "COPY", "AND_INV", "NOOP", "XOR", "OR",177"NOR", "EQUIV", "INVERTED", "OR_REV", "COPY_INV", "OR_INV", "NAND", "SET",178};179180static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) {181// For GE_PROJMAP_UV, we can ignore m[8] since it multiplies to zero.182return m[2] != 0.0f || m[5] != 0.0f || (m[8] != 0.0f && mode != GE_PROJMAP_UV) || m[11] != 1.0f;183}184185std::string FragmentShaderDesc(const FShaderID &id) {186std::stringstream desc;187desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);188if (id.Bit(FS_BIT_CLEARMODE)) desc << "Clear ";189if (id.Bit(FS_BIT_DO_TEXTURE)) desc << (id.Bit(FS_BIT_3D_TEXTURE) ? "Tex3D " : "Tex ");190if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";191if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";192if (id.Bit(FS_BIT_LMODE)) desc << "LM ";193if (id.Bit(FS_BIT_TEXALPHA)) desc << "TexAlpha ";194if (id.Bit(FS_BIT_DOUBLE_COLOR)) desc << "Double ";195if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";196if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";197if (id.Bit(FS_BIT_UBERSHADER)) desc << "FragUber ";198if (id.Bit(FS_BIT_DEPTH_TEST_NEVER)) desc << "DepthNever ";199switch ((ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2)) {200case ShaderDepalMode::OFF: break;201case ShaderDepalMode::NORMAL: desc << "Depal "; break;202case ShaderDepalMode::SMOOTHED: desc << "SmoothDepal "; break;203case ShaderDepalMode::CLUT8_8888: desc << "CLUT8From8888Depal"; break;204}205if (id.Bit(FS_BIT_COLOR_WRITEMASK)) desc << "WriteMask ";206if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {207desc << "TClamp";208if (id.Bit(FS_BIT_CLAMP_S)) desc << "S";209if (id.Bit(FS_BIT_CLAMP_T)) desc << "T";210desc << " ";211}212int blendBits = id.Bits(FS_BIT_REPLACE_BLEND, 3);213if (blendBits) {214switch (blendBits) {215case ReplaceBlendType::REPLACE_BLEND_BLUE_TO_ALPHA:216desc << "BlueToAlpha_" << "A:" << id.Bits(FS_BIT_BLENDFUNC_A, 4);217break;218default:219desc << "ReplaceBlend_" << id.Bits(FS_BIT_REPLACE_BLEND, 3)220<< "A:" << id.Bits(FS_BIT_BLENDFUNC_A, 4)221<< "_B:" << id.Bits(FS_BIT_BLENDFUNC_B, 4)222<< "_Eq:" << id.Bits(FS_BIT_BLENDEQ, 3) << " ";223break;224}225}226227switch (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)) {228case REPLACE_ALPHA_NO: break;229case REPLACE_ALPHA_YES: desc << "StenToAlpha "; break;230case REPLACE_ALPHA_DUALSOURCE: desc << "StenToAlphaDual "; break;231}232if (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2) != REPLACE_ALPHA_NO) {233switch (id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4)) {234case STENCIL_VALUE_UNIFORM: desc << "StenUniform "; break;235case STENCIL_VALUE_ZERO: desc << "Sten0 "; break;236case STENCIL_VALUE_ONE: desc << "Sten1 "; break;237case STENCIL_VALUE_KEEP: desc << "StenKeep "; break;238case STENCIL_VALUE_INVERT: desc << "StenInv "; break;239case STENCIL_VALUE_INCR_4: desc << "StenIncr4 "; break;240case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break;241case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break;242case STENCIL_VALUE_DECR_8: desc << "StenDecr8 "; break;243default: desc << "StenUnknown "; break;244}245} else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {246desc << "StenOff ";247}248if (id.Bit(FS_BIT_DO_TEXTURE)) {249switch (id.Bits(FS_BIT_TEXFUNC, 3)) {250case GE_TEXFUNC_ADD: desc << "TFuncAdd "; break;251case GE_TEXFUNC_BLEND: desc << "TFuncBlend "; break;252case GE_TEXFUNC_DECAL: desc << "TFuncDecal "; break;253case GE_TEXFUNC_MODULATE: desc << "TFuncMod "; break;254case GE_TEXFUNC_REPLACE: desc << "TFuncRepl "; break;255default: desc << "TFuncUnk "; break;256}257}258259if (id.Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc << "AlphaTest0 " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";260else if (id.Bit(FS_BIT_ALPHA_TEST)) desc << "AlphaTest " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";261if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc << "ColorTest0 " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match;262else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match263if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero ";264if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround ";265int logicMode = id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4);266if ((logicMode != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "RLogic(" << logicFuncs[logicMode] << ")";267if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray ";268if (id.Bit(FS_BIT_STEREO)) desc << "Stereo ";269if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc << "(fetch)";270return desc.str();271}272273bool FragmentIdNeedsFramebufferRead(const FShaderID &id) {274return id.Bit(FS_BIT_COLOR_WRITEMASK) ||275id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY ||276(ReplaceBlendType)id.Bits(FS_BIT_REPLACE_BLEND, 3) == REPLACE_BLEND_READ_FRAMEBUFFER;277}278279// Here we must take all the bits of the gstate that determine what the fragment shader will280// look like, and concatenate them together into an ID.281void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs) {282FShaderID id;283if (gstate.isModeClear()) {284// We only need one clear shader, so let's ignore the rest of the bits.285id.SetBit(FS_BIT_CLEARMODE);286} else {287bool isModeThrough = gstate.isModeThrough();288bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;289bool enableFog = gstate.isFogEnabled() && !isModeThrough;290bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue();291bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();292bool enableColorDouble = gstate.isColorDoublingEnabled();293bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix, gstate.getUVProjMode()));294bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT;295296bool enableTexAlpha = gstate.isTextureAlphaUsed();297298bool uberShader = gstate_c.Use(GPU_USE_FRAGMENT_UBERSHADER);299300ShaderDepalMode shaderDepalMode = gstate_c.shaderDepalMode;301302bool colorWriteMask = pipelineState.maskState.applyFramebufferRead;303ReplaceBlendType replaceBlend = pipelineState.blendState.replaceBlend;304GELogicOp replaceLogicOpType = pipelineState.logicState.applyFramebufferRead ? pipelineState.logicState.logicOp : GE_LOGIC_COPY;305306SimulateLogicOpType simulateLogicOpType = pipelineState.blendState.simulateLogicOpType;307ReplaceAlphaType stencilToAlpha = pipelineState.blendState.replaceAlphaWithStencil;308309if (gstate.isTextureMapEnabled()) {310id.SetBit(FS_BIT_DO_TEXTURE);311id.SetBits(FS_BIT_TEXFUNC, 3, gstate.getTextureFunction());312if (gstate_c.needShaderTexClamp) {313// 4 bits total.314id.SetBit(FS_BIT_SHADER_TEX_CLAMP);315id.SetBit(FS_BIT_CLAMP_S, gstate.isTexCoordClampedS());316id.SetBit(FS_BIT_CLAMP_T, gstate.isTexCoordClampedT());317}318id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);319id.SetBits(FS_BIT_SHADER_DEPAL_MODE, 2, (int)shaderDepalMode);320id.SetBit(FS_BIT_3D_TEXTURE, gstate_c.curTextureIs3D);321}322323id.SetBit(FS_BIT_LMODE, lmode);324325if (enableAlphaTest) {326// 5 bits total.327id.SetBit(FS_BIT_ALPHA_TEST);328id.SetBits(FS_BIT_ALPHA_TEST_FUNC, 3, gstate.getAlphaTestFunction());329id.SetBit(FS_BIT_ALPHA_AGAINST_ZERO, IsAlphaTestAgainstZero());330id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());331}332if (enableColorTest) {333// 4 bits total.334id.SetBit(FS_BIT_COLOR_TEST);335id.SetBits(FS_BIT_COLOR_TEST_FUNC, 2, gstate.getColorTestFunction());336id.SetBit(FS_BIT_COLOR_AGAINST_ZERO, IsColorTestAgainstZero());337// This is alos set in enableAlphaTest - color test is uncommon, but we can skip discard the same way.338id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());339}340341id.SetBit(FS_BIT_ENABLE_FOG, enableFog); // TODO: Will be moved back to the ubershader.342343id.SetBit(FS_BIT_UBERSHADER, uberShader);344if (!uberShader) {345id.SetBit(FS_BIT_TEXALPHA, enableTexAlpha);346id.SetBit(FS_BIT_DOUBLE_COLOR, enableColorDouble);347}348349id.SetBit(FS_BIT_DO_TEXTURE_PROJ, doTextureProjection);350351// 2 bits352id.SetBits(FS_BIT_STENCIL_TO_ALPHA, 2, stencilToAlpha);353354if (stencilToAlpha != REPLACE_ALPHA_NO) {355// 4 bits356id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType());357}358359// 2 bits.360id.SetBits(FS_BIT_SIMULATE_LOGIC_OP_TYPE, 2, simulateLogicOpType);361362// 4 bits. Set to GE_LOGIC_COPY if not used, which does nothing in the shader generator.363id.SetBits(FS_BIT_REPLACE_LOGIC_OP, 4, (int)replaceLogicOpType);364365// If replaceBlend == REPLACE_BLEND_STANDARD (or REPLACE_BLEND_NO) nothing is done, so we kill these bits.366if (replaceBlend == REPLACE_BLEND_BLUE_TO_ALPHA) {367id.SetBits(FS_BIT_REPLACE_BLEND, 3, replaceBlend);368id.SetBits(FS_BIT_BLENDFUNC_A, 4, gstate.getBlendFuncA());369} else if (replaceBlend > REPLACE_BLEND_STANDARD) {370// 3 bits.371id.SetBits(FS_BIT_REPLACE_BLEND, 3, replaceBlend);372// 11 bits total.373id.SetBits(FS_BIT_BLENDEQ, 3, gstate.getBlendEq());374id.SetBits(FS_BIT_BLENDFUNC_A, 4, gstate.getBlendFuncA());375id.SetBits(FS_BIT_BLENDFUNC_B, 4, gstate.getBlendFuncB());376}377id.SetBit(FS_BIT_FLATSHADE, doFlatShading);378id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask);379380// All framebuffers are array textures in Vulkan now.381if (gstate_c.textureIsArray && gstate_c.Use(GPU_USE_FRAMEBUFFER_ARRAYS)) {382id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE);383}384385// Stereo support386if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {387id.SetBit(FS_BIT_STEREO);388}389390if (g_Config.bVendorBugChecksEnabled) {391if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO) || bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI)) {392// On Adreno, the workaround is safe, so we do simple checks.393bool stencilWithoutDepth = (!gstate.isDepthTestEnabled() || !gstate.isDepthWriteEnabled()) && !IsStencilTestOutputDisabled();394if (stencilWithoutDepth) {395id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, stencilWithoutDepth);396}397}398}399400// Forcibly disable NEVER + depth-write on Mali.401// TODO: Take this from computed depth test instead of directly from the gstate.402// That will take more refactoring though.403if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI) &&404gstate.getDepthTestFunction() == GE_COMP_NEVER && gstate.isDepthTestEnabled()) {405id.SetBit(FS_BIT_DEPTH_TEST_NEVER);406}407408// In case the USE flag changes (for example, in multisampling we might disable input attachments),409// we don't want to accidentally use the wrong cached shader here. So moved it to a bit.410if (FragmentIdNeedsFramebufferRead(id)) {411if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) {412id.SetBit(FS_BIT_USE_FRAMEBUFFER_FETCH);413}414}415}416417*id_out = id;418}419420std::string GeometryShaderDesc(const GShaderID &id) {421std::stringstream desc;422desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);423if (id.Bit(GS_BIT_ENABLED)) desc << "ENABLED ";424if (id.Bit(GS_BIT_DO_TEXTURE)) desc << "TEX ";425if (id.Bit(GS_BIT_LMODE)) desc << "LM ";426return desc.str();427}428429void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim) {430GShaderID id;431// Early out.432if (!gstate_c.Use(GPU_USE_GS_CULLING)) {433*id_out = id;434return;435}436437bool isModeThrough = gstate.isModeThrough();438bool isCurve = gstate_c.submitType != SubmitType::DRAW;439bool isTriangle = prim == GE_PRIM_TRIANGLES || prim == GE_PRIM_TRIANGLE_FAN || prim == GE_PRIM_TRIANGLE_STRIP;440441bool vertexRangeCulling = !isCurve;442bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !gstate_c.Use(GPU_USE_CLIP_DISTANCE);443444// Only use this for triangle primitives, and if we actually need it.445if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle) {446*id_out = id;447return;448}449450id.SetBit(GS_BIT_ENABLED, true);451// Vertex range culling doesn't seem tno happen for spline/bezier, see #11692.452id.SetBit(GS_BIT_CURVE, isCurve);453454if (gstate.isModeClear()) {455// No attribute bits.456} else {457bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;458459id.SetBit(GS_BIT_LMODE, lmode);460if (gstate.isTextureMapEnabled()) {461id.SetBit(GS_BIT_DO_TEXTURE);462}463}464465*id_out = id;466}467468469