Convert BPMemory to BitField and enum class

Additional changes:
- For TevStageCombiner's ColorCombiner and AlphaCombiner, op/comparison and scale/compare_mode have been split as there are different meanings and enums if bias is set to compare.  (Shift has also been renamed to scale)
- In TexMode0, min_filter has been split into min_mip and min_filter.
- In TexImage1, image_type is now cache_manually_managed.
- The unused bit in GenMode is now exposed.
- LPSize's lineaspect is now named adjust_for_aspect_ratio.
This commit is contained in:
Pokechu22 2021-02-10 18:11:31 -08:00
parent db8ced7e4e
commit 70f9fc4e75
33 changed files with 1553 additions and 1236 deletions

View file

@ -378,7 +378,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state)
D3D11_LOGIC_OP_COPY_INVERTED, D3D11_LOGIC_OP_OR_INVERTED, D3D11_LOGIC_OP_NAND, D3D11_LOGIC_OP_COPY_INVERTED, D3D11_LOGIC_OP_OR_INVERTED, D3D11_LOGIC_OP_NAND,
D3D11_LOGIC_OP_SET}}; D3D11_LOGIC_OP_SET}};
tdesc.LogicOpEnable = TRUE; tdesc.LogicOpEnable = TRUE;
tdesc.LogicOp = logic_ops[state.logicmode]; tdesc.LogicOp = logic_ops[u32(state.logicmode.Value())];
ComPtr<ID3D11BlendState1> res; ComPtr<ID3D11BlendState1> res;
HRESULT hr = D3D::device1->CreateBlendState1(&desc, res.GetAddressOf()); HRESULT hr = D3D::device1->CreateBlendState1(&desc, res.GetAddressOf());
@ -416,10 +416,10 @@ ID3D11BlendState* StateCache::Get(BlendingState state)
use_dual_source ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC_ALPHA, use_dual_source ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC_ALPHA,
D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}}; D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}};
tdesc.SrcBlend = src_factors[state.srcfactor]; tdesc.SrcBlend = src_factors[u32(state.srcfactor.Value())];
tdesc.SrcBlendAlpha = src_factors[state.srcfactoralpha]; tdesc.SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
tdesc.DestBlend = dst_factors[state.dstfactor]; tdesc.DestBlend = dst_factors[u32(state.dstfactor.Value())];
tdesc.DestBlendAlpha = dst_factors[state.dstfactoralpha]; tdesc.DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
tdesc.BlendOp = state.subtract ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; tdesc.BlendOp = state.subtract ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD;
tdesc.BlendOpAlpha = state.subtractAlpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; tdesc.BlendOpAlpha = state.subtractAlpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD;
@ -441,7 +441,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state)
D3D11_RASTERIZER_DESC desc = {}; D3D11_RASTERIZER_DESC desc = {};
desc.FillMode = D3D11_FILL_SOLID; desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = cull_modes[state.cullmode]; desc.CullMode = cull_modes[u32(state.cullmode.Value())];
desc.ScissorEnable = TRUE; desc.ScissorEnable = TRUE;
ComPtr<ID3D11RasterizerState> res; ComPtr<ID3D11RasterizerState> res;
@ -477,7 +477,7 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state)
depthdc.DepthEnable = TRUE; depthdc.DepthEnable = TRUE;
depthdc.DepthWriteMask = depthdc.DepthWriteMask =
state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
depthdc.DepthFunc = d3dCmpFuncs[state.func]; depthdc.DepthFunc = d3dCmpFuncs[u32(state.func.Value())];
} }
else else
{ {

View file

@ -66,7 +66,7 @@ static void GetD3DRasterizerDesc(D3D12_RASTERIZER_DESC* desc, const Rasterizatio
{D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_BACK, D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_FRONT}}; {D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_BACK, D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_FRONT}};
desc->FillMode = D3D12_FILL_MODE_SOLID; desc->FillMode = D3D12_FILL_MODE_SOLID;
desc->CullMode = cull_modes[rs_state.cullmode]; desc->CullMode = cull_modes[u32(rs_state.cullmode.Value())];
desc->MultisampleEnable = fb_state.samples > 1; desc->MultisampleEnable = fb_state.samples > 1;
} }
@ -80,7 +80,7 @@ static void GetD3DDepthDesc(D3D12_DEPTH_STENCIL_DESC* desc, const DepthState& st
D3D12_COMPARISON_FUNC_ALWAYS}}; D3D12_COMPARISON_FUNC_ALWAYS}};
desc->DepthEnable = state.testenable; desc->DepthEnable = state.testenable;
desc->DepthFunc = compare_funcs[state.func]; desc->DepthFunc = compare_funcs[u32(state.func.Value())];
desc->DepthWriteMask = desc->DepthWriteMask =
state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
} }
@ -135,24 +135,24 @@ static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
rtblend->BlendOpAlpha = state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD; rtblend->BlendOpAlpha = state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
if (state.usedualsrc) if (state.usedualsrc)
{ {
rtblend->SrcBlend = src_dual_src_factors[state.srcfactor]; rtblend->SrcBlend = src_dual_src_factors[u32(state.srcfactor.Value())];
rtblend->SrcBlendAlpha = src_dual_src_factors[state.srcfactoralpha]; rtblend->SrcBlendAlpha = src_dual_src_factors[u32(state.srcfactoralpha.Value())];
rtblend->DestBlend = dst_dual_src_factors[state.dstfactor]; rtblend->DestBlend = dst_dual_src_factors[u32(state.dstfactor.Value())];
rtblend->DestBlendAlpha = dst_dual_src_factors[state.dstfactoralpha]; rtblend->DestBlendAlpha = dst_dual_src_factors[u32(state.dstfactoralpha.Value())];
} }
else else
{ {
rtblend->SrcBlend = src_factors[state.srcfactor]; rtblend->SrcBlend = src_factors[u32(state.srcfactor.Value())];
rtblend->SrcBlendAlpha = src_factors[state.srcfactoralpha]; rtblend->SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
rtblend->DestBlend = dst_factors[state.dstfactor]; rtblend->DestBlend = dst_factors[u32(state.dstfactor.Value())];
rtblend->DestBlendAlpha = dst_factors[state.dstfactoralpha]; rtblend->DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
} }
} }
else else
{ {
rtblend->LogicOpEnable = state.logicopenable; rtblend->LogicOpEnable = state.logicopenable;
if (state.logicopenable) if (state.logicopenable)
rtblend->LogicOp = logic_ops[state.logicmode]; rtblend->LogicOp = logic_ops[u32(state.logicmode.Value())];
} }
} }

View file

@ -1140,11 +1140,11 @@ void Renderer::ApplyRasterizationState(const RasterizationState state)
return; return;
// none, ccw, cw, ccw // none, ccw, cw, ccw
if (state.cullmode != GenMode::CULL_NONE) if (state.cullmode != CullMode::None)
{ {
// TODO: GX_CULL_ALL not supported, yet! // TODO: GX_CULL_ALL not supported, yet!
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glFrontFace(state.cullmode == GenMode::CULL_FRONT ? GL_CCW : GL_CW); glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
} }
else else
{ {
@ -1166,7 +1166,7 @@ void Renderer::ApplyDepthState(const DepthState state)
{ {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE); glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[state.func]); glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
} }
else else
{ {
@ -1229,8 +1229,10 @@ void Renderer::ApplyBlendingState(const BlendingState state)
GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD; GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD; GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
glBlendEquationSeparate(equation, equationAlpha); glBlendEquationSeparate(equation, equationAlpha);
glBlendFuncSeparate(src_factors[state.srcfactor], dst_factors[state.dstfactor], glBlendFuncSeparate(src_factors[u32(state.srcfactor.Value())],
src_factors[state.srcfactoralpha], dst_factors[state.dstfactoralpha]); dst_factors[u32(state.dstfactor.Value())],
src_factors[u32(state.srcfactoralpha.Value())],
dst_factors[u32(state.dstfactoralpha.Value())]);
} }
const GLenum logic_op_codes[16] = { const GLenum logic_op_codes[16] = {
@ -1244,7 +1246,7 @@ void Renderer::ApplyBlendingState(const BlendingState state)
if (state.logicopenable) if (state.logicopenable)
{ {
glEnable(GL_COLOR_LOGIC_OP); glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(logic_op_codes[state.logicmode]); glLogicOp(logic_op_codes[u32(state.logicmode.Value())]);
} }
else else
{ {

View file

@ -489,13 +489,16 @@ bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const Outp
backface = normalZDir <= 0.0f; backface = normalZDir <= 0.0f;
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing // TODO: Are these tests / the definition of backface above backwards?
if ((bpmem.genMode.cullmode == CullMode::Back || bpmem.genMode.cullmode == CullMode::All) &&
!backface) // cull frontfacing
{ {
INCSTAT(g_stats.this_frame.num_triangles_culled) INCSTAT(g_stats.this_frame.num_triangles_culled)
return false; return false;
} }
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing if ((bpmem.genMode.cullmode == CullMode::Front || bpmem.genMode.cullmode == CullMode::All) &&
backface) // cull backfacing
{ {
INCSTAT(g_stats.this_frame.num_triangles_culled) INCSTAT(g_stats.this_frame.num_triangles_culled)
return false; return false;

View file

@ -41,12 +41,12 @@ static void SetPixelAlphaOnly(u32 offset, u8 a)
{ {
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::Z24: case PixelFormat::Z24:
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
// do nothing // do nothing
break; break;
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
{ {
u32 a32 = a; u32 a32 = a;
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
@ -56,8 +56,7 @@ static void SetPixelAlphaOnly(u32 offset, u8 a)
} }
break; break;
default: default:
ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format);
static_cast<int>(bpmem.zcontrol.pixel_format));
break; break;
} }
} }
@ -66,8 +65,8 @@ static void SetPixelColorOnly(u32 offset, u8* rgb)
{ {
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::Z24: case PixelFormat::Z24:
{ {
u32 src = *(u32*)rgb; u32 src = *(u32*)rgb;
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
@ -76,7 +75,7 @@ static void SetPixelColorOnly(u32 offset, u8* rgb)
*dst = val; *dst = val;
} }
break; break;
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
{ {
u32 src = *(u32*)rgb; u32 src = *(u32*)rgb;
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
@ -87,7 +86,7 @@ static void SetPixelColorOnly(u32 offset, u8* rgb)
*dst = val; *dst = val;
} }
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
{ {
INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet");
u32 src = *(u32*)rgb; u32 src = *(u32*)rgb;
@ -98,8 +97,7 @@ static void SetPixelColorOnly(u32 offset, u8* rgb)
} }
break; break;
default: default:
ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format);
static_cast<int>(bpmem.zcontrol.pixel_format));
break; break;
} }
} }
@ -108,8 +106,8 @@ static void SetPixelAlphaColor(u32 offset, u8* color)
{ {
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::Z24: case PixelFormat::Z24:
{ {
u32 src = *(u32*)color; u32 src = *(u32*)color;
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
@ -118,7 +116,7 @@ static void SetPixelAlphaColor(u32 offset, u8* color)
*dst = val; *dst = val;
} }
break; break;
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
{ {
u32 src = *(u32*)color; u32 src = *(u32*)color;
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
@ -130,7 +128,7 @@ static void SetPixelAlphaColor(u32 offset, u8* color)
*dst = val; *dst = val;
} }
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
{ {
INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet");
u32 src = *(u32*)color; u32 src = *(u32*)color;
@ -141,8 +139,7 @@ static void SetPixelAlphaColor(u32 offset, u8* color)
} }
break; break;
default: default:
ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format);
static_cast<int>(bpmem.zcontrol.pixel_format));
break; break;
} }
} }
@ -154,23 +151,22 @@ static u32 GetPixelColor(u32 offset)
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::Z24: case PixelFormat::Z24:
return 0xff | ((src & 0x00ffffff) << 8); return 0xff | ((src & 0x00ffffff) << 8);
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
return Convert6To8(src & 0x3f) | // Alpha return Convert6To8(src & 0x3f) | // Alpha
Convert6To8((src >> 6) & 0x3f) << 8 | // Blue Convert6To8((src >> 6) & 0x3f) << 8 | // Blue
Convert6To8((src >> 12) & 0x3f) << 16 | // Green Convert6To8((src >> 12) & 0x3f) << 16 | // Green
Convert6To8((src >> 18) & 0x3f) << 24; // Red Convert6To8((src >> 18) & 0x3f) << 24; // Red
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet");
return 0xff | ((src & 0x00ffffff) << 8); return 0xff | ((src & 0x00ffffff) << 8);
default: default:
ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format);
static_cast<int>(bpmem.zcontrol.pixel_format));
return 0; return 0;
} }
} }
@ -179,9 +175,9 @@ static void SetPixelDepth(u32 offset, u32 depth)
{ {
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
case PEControl::Z24: case PixelFormat::Z24:
{ {
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
u32 val = *dst & 0xff000000; u32 val = *dst & 0xff000000;
@ -189,7 +185,7 @@ static void SetPixelDepth(u32 offset, u32 depth)
*dst = val; *dst = val;
} }
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
{ {
INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet");
u32* dst = (u32*)&efb[offset]; u32* dst = (u32*)&efb[offset];
@ -199,8 +195,7 @@ static void SetPixelDepth(u32 offset, u32 depth)
} }
break; break;
default: default:
ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format);
static_cast<int>(bpmem.zcontrol.pixel_format));
break; break;
} }
} }
@ -211,59 +206,58 @@ static u32 GetPixelDepth(u32 offset)
switch (bpmem.zcontrol.pixel_format) switch (bpmem.zcontrol.pixel_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
case PEControl::Z24: case PixelFormat::Z24:
{ {
depth = (*(u32*)&efb[offset]) & 0x00ffffff; depth = (*(u32*)&efb[offset]) & 0x00ffffff;
} }
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
{ {
INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet");
depth = (*(u32*)&efb[offset]) & 0x00ffffff; depth = (*(u32*)&efb[offset]) & 0x00ffffff;
} }
break; break;
default: default:
ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format);
static_cast<int>(bpmem.zcontrol.pixel_format));
break; break;
} }
return depth; return depth;
} }
static u32 GetSourceFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) static u32 GetSourceFactor(u8* srcClr, u8* dstClr, SrcBlendFactor mode)
{ {
switch (mode) switch (mode)
{ {
case BlendMode::ZERO: case SrcBlendFactor::Zero:
return 0; return 0;
case BlendMode::ONE: case SrcBlendFactor::One:
return 0xffffffff; return 0xffffffff;
case BlendMode::DSTCLR: case SrcBlendFactor::DstClr:
return *(u32*)dstClr; return *(u32*)dstClr;
case BlendMode::INVDSTCLR: case SrcBlendFactor::InvDstClr:
return 0xffffffff - *(u32*)dstClr; return 0xffffffff - *(u32*)dstClr;
case BlendMode::SRCALPHA: case SrcBlendFactor::SrcAlpha:
{ {
u8 alpha = srcClr[ALP_C]; u8 alpha = srcClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor; return factor;
} }
case BlendMode::INVSRCALPHA: case SrcBlendFactor::InvSrcAlpha:
{ {
u8 alpha = 0xff - srcClr[ALP_C]; u8 alpha = 0xff - srcClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor; return factor;
} }
case BlendMode::DSTALPHA: case SrcBlendFactor::DstAlpha:
{ {
u8 alpha = dstClr[ALP_C]; u8 alpha = dstClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor; return factor;
} }
case BlendMode::INVDSTALPHA: case SrcBlendFactor::InvDstAlpha:
{ {
u8 alpha = 0xff - dstClr[ALP_C]; u8 alpha = 0xff - dstClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
@ -274,37 +268,37 @@ static u32 GetSourceFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode)
return 0; return 0;
} }
static u32 GetDestinationFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) static u32 GetDestinationFactor(u8* srcClr, u8* dstClr, DstBlendFactor mode)
{ {
switch (mode) switch (mode)
{ {
case BlendMode::ZERO: case DstBlendFactor::Zero:
return 0; return 0;
case BlendMode::ONE: case DstBlendFactor::One:
return 0xffffffff; return 0xffffffff;
case BlendMode::SRCCLR: case DstBlendFactor::SrcClr:
return *(u32*)srcClr; return *(u32*)srcClr;
case BlendMode::INVSRCCLR: case DstBlendFactor::InvSrcClr:
return 0xffffffff - *(u32*)srcClr; return 0xffffffff - *(u32*)srcClr;
case BlendMode::SRCALPHA: case DstBlendFactor::SrcAlpha:
{ {
u8 alpha = srcClr[ALP_C]; u8 alpha = srcClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor; return factor;
} }
case BlendMode::INVSRCALPHA: case DstBlendFactor::InvSrcAlpha:
{ {
u8 alpha = 0xff - srcClr[ALP_C]; u8 alpha = 0xff - srcClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor; return factor;
} }
case BlendMode::DSTALPHA: case DstBlendFactor::DstAlpha:
{ {
u8 alpha = dstClr[ALP_C] & 0xff; u8 alpha = dstClr[ALP_C] & 0xff;
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor; return factor;
} }
case BlendMode::INVDSTALPHA: case DstBlendFactor::InvDstAlpha:
{ {
u8 alpha = 0xff - dstClr[ALP_C]; u8 alpha = 0xff - dstClr[ALP_C];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
@ -337,56 +331,56 @@ static void BlendColor(u8* srcClr, u8* dstClr)
} }
} }
static void LogicBlend(u32 srcClr, u32* dstClr, BlendMode::LogicOp op) static void LogicBlend(u32 srcClr, u32* dstClr, LogicOp op)
{ {
switch (op) switch (op)
{ {
case BlendMode::CLEAR: case LogicOp::Clear:
*dstClr = 0; *dstClr = 0;
break; break;
case BlendMode::AND: case LogicOp::And:
*dstClr = srcClr & *dstClr; *dstClr = srcClr & *dstClr;
break; break;
case BlendMode::AND_REVERSE: case LogicOp::AndReverse:
*dstClr = srcClr & (~*dstClr); *dstClr = srcClr & (~*dstClr);
break; break;
case BlendMode::COPY: case LogicOp::Copy:
*dstClr = srcClr; *dstClr = srcClr;
break; break;
case BlendMode::AND_INVERTED: case LogicOp::AndInverted:
*dstClr = (~srcClr) & *dstClr; *dstClr = (~srcClr) & *dstClr;
break; break;
case BlendMode::NOOP: case LogicOp::NoOp:
// Do nothing // Do nothing
break; break;
case BlendMode::XOR: case LogicOp::Xor:
*dstClr = srcClr ^ *dstClr; *dstClr = srcClr ^ *dstClr;
break; break;
case BlendMode::OR: case LogicOp::Or:
*dstClr = srcClr | *dstClr; *dstClr = srcClr | *dstClr;
break; break;
case BlendMode::NOR: case LogicOp::Nor:
*dstClr = ~(srcClr | *dstClr); *dstClr = ~(srcClr | *dstClr);
break; break;
case BlendMode::EQUIV: case LogicOp::Equiv:
*dstClr = ~(srcClr ^ *dstClr); *dstClr = ~(srcClr ^ *dstClr);
break; break;
case BlendMode::INVERT: case LogicOp::Invert:
*dstClr = ~*dstClr; *dstClr = ~*dstClr;
break; break;
case BlendMode::OR_REVERSE: case LogicOp::OrReverse:
*dstClr = srcClr | (~*dstClr); *dstClr = srcClr | (~*dstClr);
break; break;
case BlendMode::COPY_INVERTED: case LogicOp::CopyInverted:
*dstClr = ~srcClr; *dstClr = ~srcClr;
break; break;
case BlendMode::OR_INVERTED: case LogicOp::OrInverted:
*dstClr = (~srcClr) | *dstClr; *dstClr = (~srcClr) | *dstClr;
break; break;
case BlendMode::NAND: case LogicOp::Nand:
*dstClr = ~(srcClr & *dstClr); *dstClr = ~(srcClr & *dstClr);
break; break;
case BlendMode::SET: case LogicOp::Set:
*dstClr = 0xffffffff; *dstClr = 0xffffffff;
break; break;
} }
@ -404,7 +398,7 @@ static void SubtractBlend(u8* srcClr, u8* dstClr)
static void Dither(u16 x, u16 y, u8* color) static void Dither(u16 x, u16 y, u8* color)
{ {
// No blending for RGB8 mode // No blending for RGB8 mode
if (!bpmem.blendmode.dither || bpmem.zcontrol.pixel_format != PEControl::PixelFormat::RGBA6_Z24) if (!bpmem.blendmode.dither || bpmem.zcontrol.pixel_format != PixelFormat::RGBA6_Z24)
return; return;
// Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering // Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering
@ -662,33 +656,33 @@ bool ZCompare(u16 x, u16 y, u32 z)
switch (bpmem.zmode.func) switch (bpmem.zmode.func)
{ {
case ZMode::NEVER: case CompareMode::Never:
pass = false; pass = false;
break; break;
case ZMode::LESS: case CompareMode::Less:
pass = z < depth; pass = z < depth;
break; break;
case ZMode::EQUAL: case CompareMode::Equal:
pass = z == depth; pass = z == depth;
break; break;
case ZMode::LEQUAL: case CompareMode::LEqual:
pass = z <= depth; pass = z <= depth;
break; break;
case ZMode::GREATER: case CompareMode::Greater:
pass = z > depth; pass = z > depth;
break; break;
case ZMode::NEQUAL: case CompareMode::NEqual:
pass = z != depth; pass = z != depth;
break; break;
case ZMode::GEQUAL: case CompareMode::GEqual:
pass = z >= depth; pass = z >= depth;
break; break;
case ZMode::ALWAYS: case CompareMode::Always:
pass = true; pass = true;
break; break;
default: default:
pass = false; pass = false;
ERROR_LOG_FMT(VIDEO, "Bad Z compare mode {}", static_cast<int>(bpmem.zmode.func)); ERROR_LOG_FMT(VIDEO, "Bad Z compare mode {}", bpmem.zmode.func);
break; break;
} }

View file

@ -173,7 +173,7 @@ static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoor
const TexMode1& tm1 = texUnit.texMode1[subTexmap]; const TexMode1& tm1 = texUnit.texMode1[subTexmap];
float sDelta, tDelta; float sDelta, tDelta;
if (tm0.diag_lod) if (tm0.diag_lod == LODType::Diagonal)
{ {
float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord]; float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
float* uv1 = rasterBlock.Pixel[1][1].Uv[texcoord]; float* uv1 = rasterBlock.Pixel[1][1].Uv[texcoord];
@ -199,7 +199,8 @@ static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoor
bias >>= 1; bias >>= 1;
lod += bias; lod += bias;
*linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter)); *linear = ((lod > 0 && tm0.min_filter == FilterMode::Linear) ||
(lod <= 0 && tm0.mag_filter == FilterMode::Linear));
// NOTE: The order of comparisons for this clamp check matters. // NOTE: The order of comparisons for this clamp check matters.
if (lod > static_cast<s32>(tm1.max_lod)) if (lod > static_cast<s32>(tm1.max_lod))

View file

@ -172,11 +172,11 @@ static inline s16 Clamp1024(s16 in)
return in > 1023 ? 1023 : (in < -1024 ? -1024 : in); return in > 1023 ? 1023 : (in < -1024 ? -1024 : in);
} }
void Tev::SetRasColor(int colorChan, int swaptable) void Tev::SetRasColor(RasColorChan colorChan, int swaptable)
{ {
switch (colorChan) switch (colorChan)
{ {
case 0: // Color0 case RasColorChan::Color0:
{ {
const u8* color = Color[0]; const u8* color = Color[0];
RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1];
@ -186,7 +186,7 @@ void Tev::SetRasColor(int colorChan, int swaptable)
RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2];
} }
break; break;
case 1: // Color1 case RasColorChan::Color1:
{ {
const u8* color = Color[1]; const u8* color = Color[1];
RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1];
@ -196,7 +196,7 @@ void Tev::SetRasColor(int colorChan, int swaptable)
RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2];
} }
break; break;
case 5: // alpha bump case RasColorChan::AlphaBump:
{ {
for (s16& comp : RasColor) for (s16& comp : RasColor)
{ {
@ -204,7 +204,7 @@ void Tev::SetRasColor(int colorChan, int swaptable)
} }
} }
break; break;
case 6: // alpha bump normalized case RasColorChan::NormalizedAlphaBump:
{ {
const u8 normalized = AlphaBump | AlphaBump >> 5; const u8 normalized = AlphaBump | AlphaBump >> 5;
for (s16& comp : RasColor) for (s16& comp : RasColor)
@ -213,8 +213,11 @@ void Tev::SetRasColor(int colorChan, int swaptable)
} }
} }
break; break;
default: // zero default:
{ {
if (colorChan != RasColorChan::Zero)
PanicAlertFmt("Invalid ras color channel: {}", colorChan);
for (s16& comp : RasColor) for (s16& comp : RasColor)
{ {
comp = 0; comp = 0;
@ -226,22 +229,24 @@ void Tev::SetRasColor(int colorChan, int swaptable)
void Tev::DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]) void Tev::DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4])
{ {
for (int i = 0; i < 3; i++) for (int i = BLU_C; i <= RED_C; i++)
{ {
const InputRegType& InputReg = inputs[BLU_C + i]; const InputRegType& InputReg = inputs[i];
const u16 c = InputReg.c + (InputReg.c >> 7); const u16 c = InputReg.c + (InputReg.c >> 7);
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
temp <<= m_ScaleLShiftLUT[cc.shift]; temp <<= m_ScaleLShiftLUT[u32(cc.scale.Value())];
temp += (cc.shift == 3) ? 0 : (cc.op == 1) ? 127 : 128; temp += (cc.scale == TevScale::Divide2) ? 0 : (cc.op == TevOp::Sub) ? 127 : 128;
temp >>= 8; temp >>= 8;
temp = cc.op ? -temp : temp; temp = cc.op == TevOp::Sub ? -temp : temp;
s32 result = ((InputReg.d + m_BiasLUT[cc.bias]) << m_ScaleLShiftLUT[cc.shift]) + temp; s32 result = ((InputReg.d + m_BiasLUT[u32(cc.bias.Value())])
result = result >> m_ScaleRShiftLUT[cc.shift]; << m_ScaleLShiftLUT[u32(cc.scale.Value())]) +
temp;
result = result >> m_ScaleRShiftLUT[u32(cc.scale.Value())];
Reg[cc.dest][BLU_C + i] = result; Reg[u32(cc.dest.Value())][i] = result;
} }
} }
@ -249,56 +254,38 @@ void Tev::DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const Inpu
{ {
for (int i = BLU_C; i <= RED_C; i++) for (int i = BLU_C; i <= RED_C; i++)
{ {
switch ((cc.shift << 1) | cc.op | 8) // encoded compare mode u32 a, b;
switch (cc.compare_mode)
{ {
case TEVCMP_R8_GT: case TevCompareMode::R8:
Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[i].c : 0); a = inputs[RED_C].a;
b = inputs[RED_C].b;
break; break;
case TEVCMP_R8_EQ: case TevCompareMode::GR16:
Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[i].c : 0); a = (inputs[GRN_C].a << 8) | inputs[RED_C].a;
b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
break; break;
case TEVCMP_GR16_GT: case TevCompareMode::BGR24:
{ a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; break;
Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0);
case TevCompareMode::RGB8:
a = inputs[i].a;
b = inputs[i].b;
break;
default:
PanicAlertFmt("Invalid compare mode {}", cc.compare_mode);
continue;
} }
break;
case TEVCMP_GR16_EQ: if (cc.comparison == TevComparison::GT)
{ Reg[u32(cc.dest.Value())][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0);
const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; else
const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; Reg[u32(cc.dest.Value())][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0);
Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0);
}
break;
case TEVCMP_BGR24_GT:
{
const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0);
}
break;
case TEVCMP_BGR24_EQ:
{
const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0);
}
break;
case TEVCMP_RGB8_GT:
Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a > inputs[i].b) ? inputs[i].c : 0);
break;
case TEVCMP_RGB8_EQ:
Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a == inputs[i].b) ? inputs[i].c : 0);
break;
}
} }
} }
@ -309,95 +296,76 @@ void Tev::DrawAlphaRegular(const TevStageCombiner::AlphaCombiner& ac, const Inpu
const u16 c = InputReg.c + (InputReg.c >> 7); const u16 c = InputReg.c + (InputReg.c >> 7);
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
temp <<= m_ScaleLShiftLUT[ac.shift]; temp <<= m_ScaleLShiftLUT[u32(ac.scale.Value())];
temp += (ac.shift != 3) ? 0 : (ac.op == 1) ? 127 : 128; temp += (ac.scale != TevScale::Divide2) ? 0 : (ac.op == TevOp::Sub) ? 127 : 128;
temp = ac.op ? (-temp >> 8) : (temp >> 8); temp = ac.op == TevOp::Sub ? (-temp >> 8) : (temp >> 8);
s32 result = ((InputReg.d + m_BiasLUT[ac.bias]) << m_ScaleLShiftLUT[ac.shift]) + temp; s32 result =
result = result >> m_ScaleRShiftLUT[ac.shift]; ((InputReg.d + m_BiasLUT[u32(ac.bias.Value())]) << m_ScaleLShiftLUT[u32(ac.scale.Value())]) +
temp;
result = result >> m_ScaleRShiftLUT[u32(ac.scale.Value())];
Reg[ac.dest][ALP_C] = result; Reg[u32(ac.dest.Value())][ALP_C] = result;
} }
void Tev::DrawAlphaCompare(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]) void Tev::DrawAlphaCompare(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4])
{ {
switch ((ac.shift << 1) | ac.op | 8) // encoded compare mode u32 a, b;
switch (ac.compare_mode)
{ {
case TEVCMP_R8_GT: case TevCompareMode::R8:
Reg[ac.dest][ALP_C] = a = inputs[RED_C].a;
inputs[ALP_C].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[ALP_C].c : 0); b = inputs[RED_C].b;
break; break;
case TEVCMP_R8_EQ: case TevCompareMode::GR16:
Reg[ac.dest][ALP_C] = a = (inputs[GRN_C].a << 8) | inputs[RED_C].a;
inputs[ALP_C].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[ALP_C].c : 0); b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
break; break;
case TEVCMP_GR16_GT: case TevCompareMode::BGR24:
{ a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0);
}
break; break;
case TEVCMP_GR16_EQ: case TevCompareMode::A8:
{ a = inputs[ALP_C].a;
const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; b = inputs[ALP_C].b;
const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0);
}
break; break;
case TEVCMP_BGR24_GT: default:
{ PanicAlertFmt("Invalid compare mode {}", ac.compare_mode);
const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; return;
const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0);
}
break;
case TEVCMP_BGR24_EQ:
{
const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0);
}
break;
case TEVCMP_A8_GT:
Reg[ac.dest][ALP_C] =
inputs[ALP_C].d + ((inputs[ALP_C].a > inputs[ALP_C].b) ? inputs[ALP_C].c : 0);
break;
case TEVCMP_A8_EQ:
Reg[ac.dest][ALP_C] =
inputs[ALP_C].d + ((inputs[ALP_C].a == inputs[ALP_C].b) ? inputs[ALP_C].c : 0);
break;
}
} }
static bool AlphaCompare(int alpha, int ref, AlphaTest::CompareMode comp) if (ac.comparison == TevComparison::GT)
Reg[u32(ac.dest.Value())][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0);
else
Reg[u32(ac.dest.Value())][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0);
}
static bool AlphaCompare(int alpha, int ref, CompareMode comp)
{ {
switch (comp) switch (comp)
{ {
case AlphaTest::ALWAYS: case CompareMode::Always:
return true; return true;
case AlphaTest::NEVER: case CompareMode::Never:
return false; return false;
case AlphaTest::LEQUAL: case CompareMode::LEqual:
return alpha <= ref; return alpha <= ref;
case AlphaTest::LESS: case CompareMode::Less:
return alpha < ref; return alpha < ref;
case AlphaTest::GEQUAL: case CompareMode::GEqual:
return alpha >= ref; return alpha >= ref;
case AlphaTest::GREATER: case CompareMode::Greater:
return alpha > ref; return alpha > ref;
case AlphaTest::EQUAL: case CompareMode::Equal:
return alpha == ref; return alpha == ref;
case AlphaTest::NEQUAL: case CompareMode::NEqual:
return alpha != ref; return alpha != ref;
default: default:
PanicAlertFmt("Invalid compare mode {}", comp);
return true; return true;
} }
} }
@ -409,38 +377,40 @@ static bool TevAlphaTest(int alpha)
switch (bpmem.alpha_test.logic) switch (bpmem.alpha_test.logic)
{ {
case 0: case AlphaTestOp::And:
return comp0 && comp1; // and return comp0 && comp1;
case 1: case AlphaTestOp::Or:
return comp0 || comp1; // or return comp0 || comp1;
case 2: case AlphaTestOp::Xor:
return comp0 ^ comp1; // xor return comp0 ^ comp1;
case 3: case AlphaTestOp::Xnor:
return !(comp0 ^ comp1); // xnor return !(comp0 ^ comp1);
default: default:
PanicAlertFmt("Invalid AlphaTestOp {}", bpmem.alpha_test.logic);
return true; return true;
} }
} }
static inline s32 WrapIndirectCoord(s32 coord, int wrapMode) static inline s32 WrapIndirectCoord(s32 coord, IndTexWrap wrapMode)
{ {
switch (wrapMode) switch (wrapMode)
{ {
case ITW_OFF: case IndTexWrap::ITW_OFF:
return coord; return coord;
case ITW_256: case IndTexWrap::ITW_256:
return (coord & ((256 << 7) - 1)); return (coord & ((256 << 7) - 1));
case ITW_128: case IndTexWrap::ITW_128:
return (coord & ((128 << 7) - 1)); return (coord & ((128 << 7) - 1));
case ITW_64: case IndTexWrap::ITW_64:
return (coord & ((64 << 7) - 1)); return (coord & ((64 << 7) - 1));
case ITW_32: case IndTexWrap::ITW_32:
return (coord & ((32 << 7) - 1)); return (coord & ((32 << 7) - 1));
case ITW_16: case IndTexWrap::ITW_16:
return (coord & ((16 << 7) - 1)); return (coord & ((16 << 7) - 1));
case ITW_0: case IndTexWrap::ITW_0:
return 0; return 0;
default: default:
PanicAlertFmt("Invalid indirect wrap mode {}", wrapMode);
return 0; return 0;
} }
} }
@ -455,56 +425,59 @@ void Tev::Indirect(unsigned int stageNum, s32 s, s32 t)
// alpha bump select // alpha bump select
switch (indirect.bs) switch (indirect.bs)
{ {
case ITBA_OFF: case IndTexBumpAlpha::Off:
AlphaBump = 0; AlphaBump = 0;
break; break;
case ITBA_S: case IndTexBumpAlpha::S:
AlphaBump = indmap[TextureSampler::ALP_SMP]; AlphaBump = indmap[TextureSampler::ALP_SMP];
break; break;
case ITBA_T: case IndTexBumpAlpha::T:
AlphaBump = indmap[TextureSampler::BLU_SMP]; AlphaBump = indmap[TextureSampler::BLU_SMP];
break; break;
case ITBA_U: case IndTexBumpAlpha::U:
AlphaBump = indmap[TextureSampler::GRN_SMP]; AlphaBump = indmap[TextureSampler::GRN_SMP];
break; break;
default:
PanicAlertFmt("Invalid alpha bump {}", indirect.bs);
return;
} }
// bias select // bias select
const s16 biasValue = indirect.fmt == ITF_8 ? -128 : 1; const s16 biasValue = indirect.fmt == IndTexFormat::ITF_8 ? -128 : 1;
s16 bias[3]; s16 bias[3];
bias[0] = indirect.bias & 1 ? biasValue : 0; bias[0] = indirect.bias_s ? biasValue : 0;
bias[1] = indirect.bias & 2 ? biasValue : 0; bias[1] = indirect.bias_t ? biasValue : 0;
bias[2] = indirect.bias & 4 ? biasValue : 0; bias[2] = indirect.bias_u ? biasValue : 0;
// format // format
switch (indirect.fmt) switch (indirect.fmt)
{ {
case ITF_8: case IndTexFormat::ITF_8:
indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0]; indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0];
indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1]; indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1];
indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2]; indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2];
AlphaBump = AlphaBump & 0xf8; AlphaBump = AlphaBump & 0xf8;
break; break;
case ITF_5: case IndTexFormat::ITF_5:
indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x1f) + bias[0]; indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x1f) + bias[0];
indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x1f) + bias[1]; indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x1f) + bias[1];
indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x1f) + bias[2]; indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x1f) + bias[2];
AlphaBump = AlphaBump & 0xe0; AlphaBump = AlphaBump & 0xe0;
break; break;
case ITF_4: case IndTexFormat::ITF_4:
indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x0f) + bias[0]; indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x0f) + bias[0];
indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x0f) + bias[1]; indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x0f) + bias[1];
indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x0f) + bias[2]; indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x0f) + bias[2];
AlphaBump = AlphaBump & 0xf0; AlphaBump = AlphaBump & 0xf0;
break; break;
case ITF_3: case IndTexFormat::ITF_3:
indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x07) + bias[0]; indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x07) + bias[0];
indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x07) + bias[1]; indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x07) + bias[1];
indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x07) + bias[2]; indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x07) + bias[2];
AlphaBump = AlphaBump & 0xf8; AlphaBump = AlphaBump & 0xf8;
break; break;
default: default:
PanicAlertFmt("Tev::Indirect"); PanicAlertFmt("Invalid indirect format {}", indirect.fmt);
return; return;
} }
@ -648,8 +621,8 @@ void Tev::Draw()
} }
// set konst for this stage // set konst for this stage
const int kc = kSel.getKC(stageOdd); const auto kc = u32(kSel.getKC(stageOdd));
const int ka = kSel.getKA(stageOdd); const auto ka = u32(kSel.getKA(stageOdd));
StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]); StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]);
StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]); StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]);
StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]); StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]);
@ -662,43 +635,43 @@ void Tev::Draw()
InputRegType inputs[4]; InputRegType inputs[4];
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
inputs[BLU_C + i].a = *m_ColorInputLUT[cc.a][i]; inputs[BLU_C + i].a = *m_ColorInputLUT[u32(cc.a.Value())][i];
inputs[BLU_C + i].b = *m_ColorInputLUT[cc.b][i]; inputs[BLU_C + i].b = *m_ColorInputLUT[u32(cc.b.Value())][i];
inputs[BLU_C + i].c = *m_ColorInputLUT[cc.c][i]; inputs[BLU_C + i].c = *m_ColorInputLUT[u32(cc.c.Value())][i];
inputs[BLU_C + i].d = *m_ColorInputLUT[cc.d][i]; inputs[BLU_C + i].d = *m_ColorInputLUT[u32(cc.d.Value())][i];
} }
inputs[ALP_C].a = *m_AlphaInputLUT[ac.a]; inputs[ALP_C].a = *m_AlphaInputLUT[u32(ac.a.Value())];
inputs[ALP_C].b = *m_AlphaInputLUT[ac.b]; inputs[ALP_C].b = *m_AlphaInputLUT[u32(ac.b.Value())];
inputs[ALP_C].c = *m_AlphaInputLUT[ac.c]; inputs[ALP_C].c = *m_AlphaInputLUT[u32(ac.c.Value())];
inputs[ALP_C].d = *m_AlphaInputLUT[ac.d]; inputs[ALP_C].d = *m_AlphaInputLUT[u32(ac.d.Value())];
if (cc.bias != 3) if (cc.bias != TevBias::Compare)
DrawColorRegular(cc, inputs); DrawColorRegular(cc, inputs);
else else
DrawColorCompare(cc, inputs); DrawColorCompare(cc, inputs);
if (cc.clamp) if (cc.clamp)
{ {
Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]); Reg[u32(cc.dest.Value())][RED_C] = Clamp255(Reg[u32(cc.dest.Value())][RED_C]);
Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]); Reg[u32(cc.dest.Value())][GRN_C] = Clamp255(Reg[u32(cc.dest.Value())][GRN_C]);
Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]); Reg[u32(cc.dest.Value())][BLU_C] = Clamp255(Reg[u32(cc.dest.Value())][BLU_C]);
} }
else else
{ {
Reg[cc.dest][RED_C] = Clamp1024(Reg[cc.dest][RED_C]); Reg[u32(cc.dest.Value())][RED_C] = Clamp1024(Reg[u32(cc.dest.Value())][RED_C]);
Reg[cc.dest][GRN_C] = Clamp1024(Reg[cc.dest][GRN_C]); Reg[u32(cc.dest.Value())][GRN_C] = Clamp1024(Reg[u32(cc.dest.Value())][GRN_C]);
Reg[cc.dest][BLU_C] = Clamp1024(Reg[cc.dest][BLU_C]); Reg[u32(cc.dest.Value())][BLU_C] = Clamp1024(Reg[u32(cc.dest.Value())][BLU_C]);
} }
if (ac.bias != 3) if (ac.bias != TevBias::Compare)
DrawAlphaRegular(ac, inputs); DrawAlphaRegular(ac, inputs);
else else
DrawAlphaCompare(ac, inputs); DrawAlphaCompare(ac, inputs);
if (ac.clamp) if (ac.clamp)
Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]); Reg[u32(ac.dest.Value())][ALP_C] = Clamp255(Reg[u32(ac.dest.Value())][ALP_C]);
else else
Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]); Reg[u32(ac.dest.Value())][ALP_C] = Clamp1024(Reg[u32(ac.dest.Value())][ALP_C]);
#if ALLOW_TEV_DUMPS #if ALLOW_TEV_DUMPS
if (g_ActiveConfig.bDumpTevStages) if (g_ActiveConfig.bDumpTevStages)
@ -712,8 +685,8 @@ void Tev::Draw()
// convert to 8 bits per component // convert to 8 bits per component
// the results of the last tev stage are put onto the screen, // the results of the last tev stage are put onto the screen,
// regardless of the used destination register - TODO: Verify! // regardless of the used destination register - TODO: Verify!
const u32 color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest; const u32 color_index = u32(bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest.Value());
const u32 alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest; const u32 alpha_index = u32(bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest.Value());
u8 output[4] = {(u8)Reg[alpha_index][ALP_C], (u8)Reg[color_index][BLU_C], u8 output[4] = {(u8)Reg[alpha_index][ALP_C], (u8)Reg[color_index][BLU_C],
(u8)Reg[color_index][GRN_C], (u8)Reg[color_index][RED_C]}; (u8)Reg[color_index][GRN_C], (u8)Reg[color_index][RED_C]};
@ -721,34 +694,36 @@ void Tev::Draw()
return; return;
// z texture // z texture
if (bpmem.ztex2.op) if (bpmem.ztex2.op != ZTexOp::Disabled)
{ {
u32 ztex = bpmem.ztex1.bias; u32 ztex = bpmem.ztex1.bias;
switch (bpmem.ztex2.type) switch (bpmem.ztex2.type)
{ {
case 0: // 8 bit case ZTexFormat::U8:
ztex += TexColor[ALP_C]; ztex += TexColor[ALP_C];
break; break;
case 1: // 16 bit case ZTexFormat::U16:
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C]; ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
break; break;
case 2: // 24 bit case ZTexFormat::U24:
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C]; ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
break; break;
default:
PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type);
} }
if (bpmem.ztex2.op == ZTEXTURE_ADD) if (bpmem.ztex2.op == ZTexOp::Add)
ztex += Position[2]; ztex += Position[2];
Position[2] = ztex & 0x00ffffff; Position[2] = ztex & 0x00ffffff;
} }
// fog // fog
if (bpmem.fog.c_proj_fsel.fsel) if (bpmem.fog.c_proj_fsel.fsel != FogType::Off)
{ {
float ze; float ze;
if (bpmem.fog.c_proj_fsel.proj == 0) if (bpmem.fog.c_proj_fsel.proj == FogProjection::Perspective)
{ {
// perspective // perspective
// ze = A/(B - (Zs >> B_SHF)) // ze = A/(B - (Zs >> B_SHF))
@ -804,17 +779,17 @@ void Tev::Draw()
switch (bpmem.fog.c_proj_fsel.fsel) switch (bpmem.fog.c_proj_fsel.fsel)
{ {
case 4: // exp case FogType::Exp:
fog = 1.0f - pow(2.0f, -8.0f * fog); fog = 1.0f - pow(2.0f, -8.0f * fog);
break; break;
case 5: // exp2 case FogType::ExpSq:
fog = 1.0f - pow(2.0f, -8.0f * fog * fog); fog = 1.0f - pow(2.0f, -8.0f * fog * fog);
break; break;
case 6: // backward exp case FogType::BackwardsExp:
fog = 1.0f - fog; fog = 1.0f - fog;
fog = pow(2.0f, -8.0f * fog); fog = pow(2.0f, -8.0f * fog);
break; break;
case 7: // backward exp2 case FogType::BackwardsExpSq:
fog = 1.0f - fog; fog = 1.0f - fog;
fog = pow(2.0f, -8.0f * fog * fog); fog = pow(2.0f, -8.0f * fog * fog);
break; break;

View file

@ -57,7 +57,7 @@ class Tev
INDIRECT = 32 INDIRECT = 32
}; };
void SetRasColor(int colorChan, int swaptable); void SetRasColor(RasColorChan colorChan, int swaptable);
void DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); void DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
void DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); void DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);

View file

@ -504,7 +504,7 @@ static void EncodeRGBA6(u8* dst, const u8* src, EFBCopyFormat format, bool yuv)
break; break;
default: default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); PanicAlertFmt("Unknown texture copy format: {}\n", format);
break; break;
} }
} }
@ -743,7 +743,7 @@ static void EncodeRGBA6halfscale(u8* dst, const u8* src, EFBCopyFormat format, b
break; break;
default: default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); PanicAlertFmt("Unknown texture copy format: {}\n", format);
break; break;
} }
} }
@ -960,7 +960,7 @@ static void EncodeRGB8(u8* dst, const u8* src, EFBCopyFormat format, bool yuv)
break; break;
default: default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); PanicAlertFmt("Unknown texture copy format: {}\n", format);
break; break;
} }
} }
@ -1192,7 +1192,7 @@ static void EncodeRGB8halfscale(u8* dst, const u8* src, EFBCopyFormat format, bo
break; break;
default: default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); PanicAlertFmt("Unknown texture copy format: {}\n", format);
break; break;
} }
} }
@ -1300,7 +1300,7 @@ static void EncodeZ24(u8* dst, const u8* src, EFBCopyFormat format)
break; break;
default: default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); PanicAlertFmt("Unknown texture copy format: {}\n", format);
break; break;
} }
} }
@ -1414,7 +1414,7 @@ static void EncodeZ24halfscale(u8* dst, const u8* src, EFBCopyFormat format)
break; break;
default: default:
PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); PanicAlertFmt("Unknown texture copy format: {}\n", format);
break; break;
} }
} }
@ -1431,16 +1431,16 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b
{ {
switch (params.efb_format) switch (params.efb_format)
{ {
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
EncodeRGBA6halfscale(dst, src, params.copy_format, params.yuv); EncodeRGBA6halfscale(dst, src, params.copy_format, params.yuv);
break; break;
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv); EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv);
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv); EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv);
break; break;
case PEControl::Z24: case PixelFormat::Z24:
EncodeZ24halfscale(dst, src, params.copy_format); EncodeZ24halfscale(dst, src, params.copy_format);
break; break;
default: default:
@ -1451,16 +1451,16 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b
{ {
switch (params.efb_format) switch (params.efb_format)
{ {
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
EncodeRGBA6(dst, src, params.copy_format, params.yuv); EncodeRGBA6(dst, src, params.copy_format, params.yuv);
break; break;
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
EncodeRGB8(dst, src, params.copy_format, params.yuv); EncodeRGB8(dst, src, params.copy_format, params.yuv);
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
EncodeRGB8(dst, src, params.copy_format, params.yuv); EncodeRGB8(dst, src, params.copy_format, params.yuv);
break; break;
case PEControl::Z24: case PixelFormat::Z24:
EncodeZ24(dst, src, params.copy_format); EncodeZ24(dst, src, params.copy_format);
break; break;
default: default:

View file

@ -8,6 +8,7 @@
#include <cmath> #include <cmath>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "VideoCommon/BPMemory.h" #include "VideoCommon/BPMemory.h"
@ -18,28 +19,30 @@
namespace TextureSampler namespace TextureSampler
{ {
static inline void WrapCoord(int* coordp, int wrapMode, int imageSize) static inline void WrapCoord(int* coordp, WrapMode wrapMode, int imageSize)
{ {
int coord = *coordp; int coord = *coordp;
switch (wrapMode) switch (wrapMode)
{ {
case 0: // clamp case WrapMode::Clamp:
coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord; coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord;
break; break;
case 1: // wrap case WrapMode::Repeat:
coord = coord % (imageSize + 1); coord = coord % (imageSize + 1);
coord = (coord < 0) ? imageSize + coord : coord; coord = (coord < 0) ? imageSize + coord : coord;
break; break;
case 2: // mirror case WrapMode::Mirror:
{ {
const int sizePlus1 = imageSize + 1; const int sizePlus1 = imageSize + 1;
const int div = coord / sizePlus1; const int div = coord / sizePlus1;
coord = coord - (div * sizePlus1); coord = coord - (div * sizePlus1);
coord = (coord < 0) ? -coord : coord; coord = (coord < 0) ? -coord : coord;
coord = (div & 1) ? imageSize - coord : coord; coord = (div & 1) ? imageSize - coord : coord;
}
break; break;
} }
default:
PanicAlertFmt("Invalid wrap mode: {}", wrapMode);
}
*coordp = coord; *coordp = coord;
} }
@ -74,10 +77,11 @@ void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample)
{ {
// use mipmap // use mipmap
baseMip = lod >> 4; baseMip = lod >> 4;
mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR); mipLinear = (lodFract && tm0.mipmap_filter == MipMode::Linear);
// if using nearest mip filter and lodFract >= 0.5 round up to next mip // if using nearest mip filter and lodFract >= 0.5 round up to next mip
baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT); if (tm0.mipmap_filter == MipMode::Point && lodFract >= 8)
baseMip++;
} }
if (mipLinear) if (mipLinear)
@ -111,12 +115,12 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
const TexMode0& tm0 = texUnit.texMode0[subTexmap]; const TexMode0& tm0 = texUnit.texMode0[subTexmap];
const TexImage0& ti0 = texUnit.texImage0[subTexmap]; const TexImage0& ti0 = texUnit.texImage0[subTexmap];
const TexTLUT& texTlut = texUnit.texTlut[subTexmap]; const TexTLUT& texTlut = texUnit.texTlut[subTexmap];
const TextureFormat texfmt = static_cast<TextureFormat>(ti0.format); const TextureFormat texfmt = ti0.format;
const TLUTFormat tlutfmt = static_cast<TLUTFormat>(texTlut.tlut_format); const TLUTFormat tlutfmt = texTlut.tlut_format;
const u8* imageSrc; const u8* imageSrc;
const u8* imageSrcOdd = nullptr; const u8* imageSrcOdd = nullptr;
if (texUnit.texImage1[subTexmap].image_type) if (texUnit.texImage1[subTexmap].cache_manually_managed)
{ {
imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE]; imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE];
if (texfmt == TextureFormat::RGBA8) if (texfmt == TextureFormat::RGBA8)
@ -188,7 +192,7 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth); WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth);
WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight); WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight);
if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].image_type)) if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].cache_manually_managed))
{ {
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, texfmt, tlut, TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, texfmt, tlut,
tlutfmt); tlutfmt);
@ -240,7 +244,7 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
WrapCoord(&imageS, tm0.wrap_s, imageWidth); WrapCoord(&imageS, tm0.wrap_s, imageWidth);
WrapCoord(&imageT, tm0.wrap_t, imageHeight); WrapCoord(&imageT, tm0.wrap_t, imageHeight);
if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].image_type)) if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].cache_manually_managed))
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, texfmt, tlut, tlutfmt); TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, texfmt, tlut, tlutfmt);
else else
TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT,

View file

@ -52,7 +52,7 @@ GetVulkanRasterizationState(const RasterizationState& state)
depth_clamp, // VkBool32 depthClampEnable depth_clamp, // VkBool32 depthClampEnable
VK_FALSE, // VkBool32 rasterizerDiscardEnable VK_FALSE, // VkBool32 rasterizerDiscardEnable
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
cull_modes[state.cullmode], // VkCullModeFlags cullMode cull_modes[u32(state.cullmode.Value())], // VkCullModeFlags cullMode
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
VK_FALSE, // VkBool32 depthBiasEnable VK_FALSE, // VkBool32 depthBiasEnable
0.0f, // float depthBiasConstantFactor 0.0f, // float depthBiasConstantFactor
@ -85,31 +85,32 @@ static VkPipelineDepthStencilStateCreateInfo GetVulkanDepthStencilState(const De
bool inverted_depth = !g_ActiveConfig.backend_info.bSupportsReversedDepthRange; bool inverted_depth = !g_ActiveConfig.backend_info.bSupportsReversedDepthRange;
switch (state.func) switch (state.func)
{ {
case ZMode::NEVER: case CompareMode::Never:
compare_op = VK_COMPARE_OP_NEVER; compare_op = VK_COMPARE_OP_NEVER;
break; break;
case ZMode::LESS: case CompareMode::Less:
compare_op = inverted_depth ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS; compare_op = inverted_depth ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS;
break; break;
case ZMode::EQUAL: case CompareMode::Equal:
compare_op = VK_COMPARE_OP_EQUAL; compare_op = VK_COMPARE_OP_EQUAL;
break; break;
case ZMode::LEQUAL: case CompareMode::LEqual:
compare_op = inverted_depth ? VK_COMPARE_OP_GREATER_OR_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL; compare_op = inverted_depth ? VK_COMPARE_OP_GREATER_OR_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL;
break; break;
case ZMode::GREATER: case CompareMode::Greater:
compare_op = inverted_depth ? VK_COMPARE_OP_LESS : VK_COMPARE_OP_GREATER; compare_op = inverted_depth ? VK_COMPARE_OP_LESS : VK_COMPARE_OP_GREATER;
break; break;
case ZMode::NEQUAL: case CompareMode::NEqual:
compare_op = VK_COMPARE_OP_NOT_EQUAL; compare_op = VK_COMPARE_OP_NOT_EQUAL;
break; break;
case ZMode::GEQUAL: case CompareMode::GEqual:
compare_op = inverted_depth ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_GREATER_OR_EQUAL; compare_op = inverted_depth ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_GREATER_OR_EQUAL;
break; break;
case ZMode::ALWAYS: case CompareMode::Always:
compare_op = VK_COMPARE_OP_ALWAYS; compare_op = VK_COMPARE_OP_ALWAYS;
break; break;
default: default:
PanicAlertFmt("Invalid compare mode {}", state.func);
compare_op = VK_COMPARE_OP_ALWAYS; compare_op = VK_COMPARE_OP_ALWAYS;
break; break;
} }
@ -150,10 +151,10 @@ static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const B
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}}; VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};
vk_state.srcColorBlendFactor = src_factors[state.srcfactor]; vk_state.srcColorBlendFactor = src_factors[u32(state.srcfactor.Value())];
vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha]; vk_state.srcAlphaBlendFactor = src_factors[u32(state.srcfactoralpha.Value())];
vk_state.dstColorBlendFactor = dst_factors[state.dstfactor]; vk_state.dstColorBlendFactor = dst_factors[u32(state.dstfactor.Value())];
vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha]; vk_state.dstAlphaBlendFactor = dst_factors[u32(state.dstfactoralpha.Value())];
} }
else else
{ {
@ -169,10 +170,10 @@ static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const B
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}}; VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};
vk_state.srcColorBlendFactor = src_factors[state.srcfactor]; vk_state.srcColorBlendFactor = src_factors[u32(state.srcfactor.Value())];
vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha]; vk_state.srcAlphaBlendFactor = src_factors[u32(state.srcfactoralpha.Value())];
vk_state.dstColorBlendFactor = dst_factors[state.dstfactor]; vk_state.dstColorBlendFactor = dst_factors[u32(state.dstfactor.Value())];
vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha]; vk_state.dstAlphaBlendFactor = dst_factors[u32(state.dstfactoralpha.Value())];
} }
if (state.colorupdate) if (state.colorupdate)
@ -211,7 +212,8 @@ GetVulkanColorBlendState(const BlendingState& state,
vk_logic_op_enable = VK_FALSE; vk_logic_op_enable = VK_FALSE;
} }
VkLogicOp vk_logic_op = vk_logic_op_enable ? vk_logic_ops[state.logicmode] : VK_LOGIC_OP_CLEAR; VkLogicOp vk_logic_op =
vk_logic_op_enable ? vk_logic_ops[u32(state.logicmode.Value())] : VK_LOGIC_OP_CLEAR;
VkPipelineColorBlendStateCreateInfo vk_state = { VkPipelineColorBlendStateCreateInfo vk_state = {
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType

View file

@ -166,9 +166,9 @@ void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha // Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF. This hopefully allows us to use the fast path in most cases. // channel to 0xFF. This hopefully allows us to use the fast path in most cases.
if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16 || if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 ||
bpmem.zcontrol.pixel_format == PEControl::RGB8_Z24 || bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 ||
bpmem.zcontrol.pixel_format == PEControl::Z24) bpmem.zcontrol.pixel_format == PixelFormat::Z24)
{ {
// Force alpha writes, and clear the alpha channel. This is different to the other backends, // Force alpha writes, and clear the alpha channel. This is different to the other backends,
// where the existing values of the alpha channel are preserved. // where the existing values of the alpha channel are preserved.

View file

@ -184,8 +184,8 @@ void ClearScreen(const MathUtil::Rectangle<int>& rc)
auto pixel_format = bpmem.zcontrol.pixel_format; auto pixel_format = bpmem.zcontrol.pixel_format;
// (1): Disable unused color channels // (1): Disable unused color channels
if (pixel_format == PEControl::RGB8_Z24 || pixel_format == PEControl::RGB565_Z16 || if (pixel_format == PixelFormat::RGB8_Z24 || pixel_format == PixelFormat::RGB565_Z16 ||
pixel_format == PEControl::Z24) pixel_format == PixelFormat::Z24)
{ {
alphaEnable = false; alphaEnable = false;
} }
@ -196,11 +196,11 @@ void ClearScreen(const MathUtil::Rectangle<int>& rc)
u32 z = bpmem.clearZValue; u32 z = bpmem.clearZValue;
// (2) drop additional accuracy // (2) drop additional accuracy
if (pixel_format == PEControl::RGBA6_Z24) if (pixel_format == PixelFormat::RGBA6_Z24)
{ {
color = RGBA8ToRGBA6ToRGBA8(color); color = RGBA8ToRGBA6ToRGBA8(color);
} }
else if (pixel_format == PEControl::RGB565_Z16) else if (pixel_format == PixelFormat::RGB565_Z16)
{ {
color = RGBA8ToRGB565ToRGBA8(color); color = RGBA8ToRGB565ToRGBA8(color);
z = Z24ToZ16ToZ24(z); z = Z24ToZ16ToZ24(z);
@ -228,29 +228,28 @@ void OnPixelFormatChange()
const auto new_format = bpmem.zcontrol.pixel_format; const auto new_format = bpmem.zcontrol.pixel_format;
g_renderer->StorePixelFormat(new_format); g_renderer->StorePixelFormat(new_format);
DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", static_cast<int>(new_format), DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", new_format, bpmem.zcontrol.zformat);
static_cast<int>(bpmem.zcontrol.zformat));
// no need to reinterpret pixel data in these cases // no need to reinterpret pixel data in these cases
if (new_format == old_format || old_format == PEControl::INVALID_FMT) if (new_format == old_format || old_format == PixelFormat::INVALID_FMT)
return; return;
// Check for pixel format changes // Check for pixel format changes
switch (old_format) switch (old_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
case PEControl::Z24: case PixelFormat::Z24:
{ {
// Z24 and RGB8_Z24 are treated equal, so just return in this case // Z24 and RGB8_Z24 are treated equal, so just return in this case
if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24)
return; return;
if (new_format == PEControl::RGBA6_Z24) if (new_format == PixelFormat::RGBA6_Z24)
{ {
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGBA6); g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGBA6);
return; return;
} }
else if (new_format == PEControl::RGB565_Z16) else if (new_format == PixelFormat::RGB565_Z16)
{ {
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGB565); g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGB565);
return; return;
@ -258,14 +257,14 @@ void OnPixelFormatChange()
} }
break; break;
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
{ {
if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24)
{ {
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB8); g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB8);
return; return;
} }
else if (new_format == PEControl::RGB565_Z16) else if (new_format == PixelFormat::RGB565_Z16)
{ {
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB565); g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB565);
return; return;
@ -273,14 +272,14 @@ void OnPixelFormatChange()
} }
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
{ {
if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24)
{ {
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGB8); g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGB8);
return; return;
} }
else if (new_format == PEControl::RGBA6_Z24) else if (new_format == PixelFormat::RGBA6_Z24)
{ {
g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGBA6); g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGBA6);
return; return;
@ -292,8 +291,7 @@ void OnPixelFormatChange()
break; break;
} }
ERROR_LOG_FMT(VIDEO, "Unhandled EFB format change: {} to {}", static_cast<int>(old_format), ERROR_LOG_FMT(VIDEO, "Unhandled EFB format change: {} to {}", old_format, new_format);
static_cast<int>(new_format));
} }
void SetInterlacingMode(const BPCmd& bp) void SetInterlacingMode(const BPCmd& bp)
@ -305,17 +303,15 @@ void SetInterlacingMode(const BPCmd& bp)
{ {
// SDK always sets bpmem.lineptwidth.lineaspect via BPMEM_LINEPTWIDTH // SDK always sets bpmem.lineptwidth.lineaspect via BPMEM_LINEPTWIDTH
// just before this cmd // just before this cmd
static constexpr std::string_view action[] = {"don't adjust", "adjust"}; DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMODE texLOD:{} lineaspect:{}", bpmem.fieldmode.texLOD,
DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMODE texLOD:{} lineaspect:{}", action[bpmem.fieldmode.texLOD], bpmem.lineptwidth.adjust_for_aspect_ratio);
action[bpmem.lineptwidth.lineaspect]);
} }
break; break;
case BPMEM_FIELDMASK: case BPMEM_FIELDMASK:
{ {
// Determines if fields will be written to EFB (always computed) // Determines if fields will be written to EFB (always computed)
static constexpr std::string_view action[] = {"skip", "write"}; DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMASK even:{} odd:{}", bpmem.fieldmask.even,
DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMASK even:{} odd:{}", action[bpmem.fieldmask.even], bpmem.fieldmask.odd);
action[bpmem.fieldmask.odd]);
} }
break; break;
default: default:

View file

@ -17,7 +17,7 @@ bool BlendMode::UseLogicOp() const
return false; return false;
// Fast path for Kirby's Return to Dreamland, they use it with dstAlpha. // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
if (logicmode == BlendMode::NOOP) if (logicmode == LogicOp::NoOp)
return false; return false;
return true; return true;

File diff suppressed because it is too large Load diff

View file

@ -91,10 +91,9 @@ static void BPWritten(const BPCmd& bp)
{ {
case BPMEM_GENMODE: // Set the Generation Mode case BPMEM_GENMODE: // Set the Generation Mode
PRIM_LOG("genmode: texgen={}, col={}, multisampling={}, tev={}, cullmode={}, ind={}, zfeeze={}", PRIM_LOG("genmode: texgen={}, col={}, multisampling={}, tev={}, cullmode={}, ind={}, zfeeze={}",
bpmem.genMode.numtexgens.Value(), bpmem.genMode.numcolchans.Value(), bpmem.genMode.numtexgens, bpmem.genMode.numcolchans, bpmem.genMode.multisampling,
bpmem.genMode.multisampling.Value(), bpmem.genMode.numtevstages.Value() + 1, bpmem.genMode.numtevstages + 1, bpmem.genMode.cullmode, bpmem.genMode.numindstages,
static_cast<u32>(bpmem.genMode.cullmode), bpmem.genMode.numindstages.Value(), bpmem.genMode.zfreeze);
bpmem.genMode.zfreeze.Value());
if (bp.changes) if (bp.changes)
PixelShaderManager::SetGenModeChanged(); PixelShaderManager::SetGenModeChanged();
@ -138,8 +137,8 @@ static void BPWritten(const BPCmd& bp)
GeometryShaderManager::SetLinePtWidthChanged(); GeometryShaderManager::SetLinePtWidthChanged();
return; return;
case BPMEM_ZMODE: // Depth Control case BPMEM_ZMODE: // Depth Control
PRIM_LOG("zmode: test={}, func={}, upd={}", bpmem.zmode.testenable.Value(), PRIM_LOG("zmode: test={}, func={}, upd={}", bpmem.zmode.testenable, bpmem.zmode.func,
bpmem.zmode.func.Value(), bpmem.zmode.updateenable.Value()); bpmem.zmode.updateenable);
SetDepthMode(); SetDepthMode();
PixelShaderManager::SetZModeControl(); PixelShaderManager::SetZModeControl();
return; return;
@ -147,10 +146,9 @@ static void BPWritten(const BPCmd& bp)
if (bp.changes & 0xFFFF) if (bp.changes & 0xFFFF)
{ {
PRIM_LOG("blendmode: en={}, open={}, colupd={}, alphaupd={}, dst={}, src={}, sub={}, mode={}", PRIM_LOG("blendmode: en={}, open={}, colupd={}, alphaupd={}, dst={}, src={}, sub={}, mode={}",
bpmem.blendmode.blendenable.Value(), bpmem.blendmode.logicopenable.Value(), bpmem.blendmode.blendenable, bpmem.blendmode.logicopenable,
bpmem.blendmode.colorupdate.Value(), bpmem.blendmode.alphaupdate.Value(), bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate, bpmem.blendmode.dstfactor,
bpmem.blendmode.dstfactor.Value(), bpmem.blendmode.srcfactor.Value(), bpmem.blendmode.srcfactor, bpmem.blendmode.subtract, bpmem.blendmode.logicmode);
bpmem.blendmode.subtract.Value(), bpmem.blendmode.logicmode.Value());
SetBlendMode(); SetBlendMode();
@ -158,8 +156,7 @@ static void BPWritten(const BPCmd& bp)
} }
return; return;
case BPMEM_CONSTANTALPHA: // Set Destination Alpha case BPMEM_CONSTANTALPHA: // Set Destination Alpha
PRIM_LOG("constalpha: alp={}, en={}", bpmem.dstalpha.alpha.Value(), PRIM_LOG("constalpha: alp={}, en={}", bpmem.dstalpha.alpha, bpmem.dstalpha.enable);
bpmem.dstalpha.enable.Value());
if (bp.changes) if (bp.changes)
{ {
PixelShaderManager::SetAlpha(); PixelShaderManager::SetAlpha();
@ -264,14 +261,14 @@ static void BPWritten(const BPCmd& bp)
const UPE_Copy PE_copy = bpmem.triggerEFBCopy; const UPE_Copy PE_copy = bpmem.triggerEFBCopy;
if (PE_copy.copy_to_xfb == 0) if (PE_copy.copy_to_xfb == 0)
{ {
// bpmem.zcontrol.pixel_format to PEControl::Z24 is when the game wants to copy from ZBuffer // bpmem.zcontrol.pixel_format to PixelFormat::Z24 is when the game wants to copy from ZBuffer
// (Zbuffer uses 24-bit Format) // (Zbuffer uses 24-bit Format)
static constexpr CopyFilterCoefficients::Values filter_coefficients = { static constexpr CopyFilterCoefficients::Values filter_coefficients = {
{0, 0, 21, 22, 21, 0, 0}}; {0, 0, 21, 22, 21, 0, 0}};
bool is_depth_copy = bpmem.zcontrol.pixel_format == PEControl::Z24; bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24;
g_texture_cache->CopyRenderTargetToTexture( g_texture_cache->CopyRenderTargetToTexture(
destAddr, PE_copy.tp_realFormat(), copy_width, copy_height, destStride, is_depth_copy, destAddr, PE_copy.tp_realFormat(), copy_width, copy_height, destStride, is_depth_copy,
srcRect, !!PE_copy.intensity_fmt, !!PE_copy.half_scale, 1.0f, 1.0f, srcRect, PE_copy.intensity_fmt, PE_copy.half_scale, 1.0f, 1.0f,
bpmem.triggerEFBCopy.clamp_top, bpmem.triggerEFBCopy.clamp_bottom, filter_coefficients); bpmem.triggerEFBCopy.clamp_top, bpmem.triggerEFBCopy.clamp_bottom, filter_coefficients);
} }
else else
@ -297,7 +294,7 @@ static void BPWritten(const BPCmd& bp)
destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom,
bpmem.copyTexSrcWH.x + 1, destStride, height, yScale); bpmem.copyTexSrcWH.x + 1, destStride, height, yScale);
bool is_depth_copy = bpmem.zcontrol.pixel_format == PEControl::Z24; bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24;
g_texture_cache->CopyRenderTargetToTexture( g_texture_cache->CopyRenderTargetToTexture(
destAddr, EFBCopyFormat::XFB, copy_width, height, destStride, is_depth_copy, srcRect, destAddr, EFBCopyFormat::XFB, copy_width, height, destStride, is_depth_copy, srcRect,
false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top,
@ -370,10 +367,9 @@ static void BPWritten(const BPCmd& bp)
PixelShaderManager::SetFogColorChanged(); PixelShaderManager::SetFogColorChanged();
return; return;
case BPMEM_ALPHACOMPARE: // Compare Alpha Values case BPMEM_ALPHACOMPARE: // Compare Alpha Values
PRIM_LOG("alphacmp: ref0={}, ref1={}, comp0={}, comp1={}, logic={}", PRIM_LOG("alphacmp: ref0={}, ref1={}, comp0={}, comp1={}, logic={}", bpmem.alpha_test.ref0,
bpmem.alpha_test.ref0.Value(), bpmem.alpha_test.ref1.Value(), bpmem.alpha_test.ref1, bpmem.alpha_test.comp0, bpmem.alpha_test.comp1,
static_cast<int>(bpmem.alpha_test.comp0), static_cast<int>(bpmem.alpha_test.comp1), bpmem.alpha_test.logic);
static_cast<int>(bpmem.alpha_test.logic));
if (bp.changes & 0xFFFF) if (bp.changes & 0xFFFF)
PixelShaderManager::SetAlpha(); PixelShaderManager::SetAlpha();
if (bp.changes) if (bp.changes)
@ -383,7 +379,7 @@ static void BPWritten(const BPCmd& bp)
} }
return; return;
case BPMEM_BIAS: // BIAS case BPMEM_BIAS: // BIAS
PRIM_LOG("ztex bias={:#x}", bpmem.ztex1.bias.Value()); PRIM_LOG("ztex bias={:#x}", bpmem.ztex1.bias);
if (bp.changes) if (bp.changes)
PixelShaderManager::SetZTextureBias(); PixelShaderManager::SetZTextureBias();
return; return;
@ -393,11 +389,7 @@ static void BPWritten(const BPCmd& bp)
PixelShaderManager::SetZTextureTypeChanged(); PixelShaderManager::SetZTextureTypeChanged();
if (bp.changes & 12) if (bp.changes & 12)
PixelShaderManager::SetZTextureOpChanged(); PixelShaderManager::SetZTextureOpChanged();
#if defined(_DEBUG) || defined(DEBUGFAST) PRIM_LOG("ztex op={}, type={}", bpmem.ztex2.op, bpmem.ztex2.type);
static constexpr std::string_view pzop[] = {"DISABLE", "ADD", "REPLACE", "?"};
static constexpr std::string_view pztype[] = {"Z8", "Z16", "Z24", "?"};
PRIM_LOG("ztex op={}, type={}", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]);
#endif
} }
return; return;
// ---------------------------------- // ----------------------------------
@ -588,15 +580,15 @@ static void BPWritten(const BPCmd& bp)
case BPMEM_TEV_COLOR_RA + 6: case BPMEM_TEV_COLOR_RA + 6:
{ {
int num = (bp.address >> 1) & 0x3; int num = (bp.address >> 1) & 0x3;
if (bpmem.tevregs[num].type_ra) if (bpmem.tevregs[num].ra.type == TevRegType::Constant)
{ {
PixelShaderManager::SetTevKonstColor(num, 0, (s32)bpmem.tevregs[num].red); PixelShaderManager::SetTevKonstColor(num, 0, bpmem.tevregs[num].ra.red);
PixelShaderManager::SetTevKonstColor(num, 3, (s32)bpmem.tevregs[num].alpha); PixelShaderManager::SetTevKonstColor(num, 3, bpmem.tevregs[num].ra.alpha);
} }
else else
{ {
PixelShaderManager::SetTevColor(num, 0, (s32)bpmem.tevregs[num].red); PixelShaderManager::SetTevColor(num, 0, bpmem.tevregs[num].ra.red);
PixelShaderManager::SetTevColor(num, 3, (s32)bpmem.tevregs[num].alpha); PixelShaderManager::SetTevColor(num, 3, bpmem.tevregs[num].ra.alpha);
} }
return; return;
} }
@ -607,15 +599,15 @@ static void BPWritten(const BPCmd& bp)
case BPMEM_TEV_COLOR_BG + 6: case BPMEM_TEV_COLOR_BG + 6:
{ {
int num = (bp.address >> 1) & 0x3; int num = (bp.address >> 1) & 0x3;
if (bpmem.tevregs[num].type_bg) if (bpmem.tevregs[num].bg.type == TevRegType::Constant)
{ {
PixelShaderManager::SetTevKonstColor(num, 1, (s32)bpmem.tevregs[num].green); PixelShaderManager::SetTevKonstColor(num, 1, bpmem.tevregs[num].bg.green);
PixelShaderManager::SetTevKonstColor(num, 2, (s32)bpmem.tevregs[num].blue); PixelShaderManager::SetTevKonstColor(num, 2, bpmem.tevregs[num].bg.blue);
} }
else else
{ {
PixelShaderManager::SetTevColor(num, 1, (s32)bpmem.tevregs[num].green); PixelShaderManager::SetTevColor(num, 1, bpmem.tevregs[num].bg.green);
PixelShaderManager::SetTevColor(num, 2, (s32)bpmem.tevregs[num].blue); PixelShaderManager::SetTevColor(num, 2, bpmem.tevregs[num].bg.blue);
} }
return; return;
} }
@ -915,15 +907,7 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
SetRegName(BPMEM_BLENDMODE); SetRegName(BPMEM_BLENDMODE);
BlendMode mode; BlendMode mode;
mode.hex = cmddata; mode.hex = cmddata;
const char* dstfactors[] = {"0", "1", "src_color", "1-src_color", *desc = fmt::format("Enable: {}\n"
"src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"};
const char* srcfactors[] = {"0", "1", "dst_color", "1-dst_color",
"src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"};
const char* logicmodes[] = {"0", "s & d", "s & ~d", "s", "~s & d", "d",
"s ^ d", "s | d", "~(s | d)", "~(s ^ d)", "~d", "s | ~d",
"~s", "~s | d", "~(s & d)", "1"};
*desc =
fmt::format("Enable: {}\n"
"Logic ops: {}\n" "Logic ops: {}\n"
"Dither: {}\n" "Dither: {}\n"
"Color write: {}\n" "Color write: {}\n"
@ -933,8 +917,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
"Subtract: {}\n" "Subtract: {}\n"
"Logic mode: {}\n", "Logic mode: {}\n",
no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither],
no_yes[mode.colorupdate], no_yes[mode.alphaupdate], dstfactors[mode.dstfactor], no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor,
srcfactors[mode.srcfactor], no_yes[mode.subtract], logicmodes[mode.logicmode]); mode.srcfactor, no_yes[mode.subtract], mode.logicmode);
} }
break; break;
@ -948,16 +932,10 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
SetRegName(BPMEM_ZCOMPARE); SetRegName(BPMEM_ZCOMPARE);
PEControl config; PEControl config;
config.hex = cmddata; config.hex = cmddata;
const char* pixel_formats[] = {"RGB8_Z24", "RGBA6_Z24", "RGB565_Z16", "Z24",
"Y8", "U8", "V8", "YUV420"};
const char* zformats[] = {
"linear", "compressed (near)", "compressed (mid)", "compressed (far)",
"inv linear", "compressed (inv near)", "compressed (inv mid)", "compressed (inv far)"};
*desc = fmt::format("EFB pixel format: {}\n" *desc = fmt::format("EFB pixel format: {}\n"
"Depth format: {}\n" "Depth format: {}\n"
"Early depth test: {}\n", "Early depth test: {}\n",
pixel_formats[config.pixel_format], zformats[config.zformat], config.pixel_format, config.zformat, no_yes[config.early_ztest]);
no_yes[config.early_ztest]);
} }
break; break;
@ -1048,7 +1026,7 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
"Mipmap filter: {}\n" "Mipmap filter: {}\n"
"Vertical scaling: {}\n" "Vertical scaling: {}\n"
"Clear: {}\n" "Clear: {}\n"
"Frame to field: 0x{:01X}\n" "Frame to field: {}\n"
"Copy to XFB: {}\n" "Copy to XFB: {}\n"
"Intensity format: {}\n" "Intensity format: {}\n"
"Automatic color conversion: {}", "Automatic color conversion: {}",
@ -1059,9 +1037,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
(copy.gamma == 0) ? (copy.gamma == 0) ?
"1.0" : "1.0" :
(copy.gamma == 1) ? "1.7" : (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?", (copy.gamma == 1) ? "1.7" : (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?",
no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field,
static_cast<u32>(copy.frame_to_field), no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]);
no_yes[copy.auto_conv]);
} }
break; break;
@ -1183,8 +1160,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
*desc = fmt::format("Texture Unit: {}\n" *desc = fmt::format("Texture Unit: {}\n"
"Width: {}\n" "Width: {}\n"
"Height: {}\n" "Height: {}\n"
"Format: {:x}\n", "Format: {}\n",
texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, u32(teximg.format)); texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, teximg.format);
} }
break; break;
@ -1208,7 +1185,7 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
"Even TMEM Height: {}\n" "Even TMEM Height: {}\n"
"Cache is manually managed: {}\n", "Cache is manually managed: {}\n",
texnum, u32(teximg.tmem_even), u32(teximg.cache_width), texnum, u32(teximg.tmem_even), u32(teximg.cache_width),
u32(teximg.cache_height), no_yes[teximg.image_type]); u32(teximg.cache_height), no_yes[teximg.cache_manually_managed]);
} }
break; break;
@ -1285,14 +1262,6 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
SetRegName(BPMEM_TEV_COLOR_ENV); SetRegName(BPMEM_TEV_COLOR_ENV);
TevStageCombiner::ColorCombiner cc; TevStageCombiner::ColorCombiner cc;
cc.hex = cmddata; cc.hex = cmddata;
const char* tevin[] = {
"prev.rgb", "prev.aaa", "c0.rgb", "c0.aaa", "c1.rgb", "c1.aaa", "c2.rgb", "c2.aaa",
"tex.rgb", "tex.aaa", "ras.rgb", "ras.aaa", "ONE", "HALF", "konst.rgb", "ZERO",
};
const char* tevbias[] = {"0", "+0.5", "-0.5", "compare"};
const char* tevop[] = {"add", "sub"};
const char* tevscale[] = {"1", "2", "4", "0.5"};
const char* tevout[] = {"prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb"};
*desc = fmt::format("Tev stage: {}\n" *desc = fmt::format("Tev stage: {}\n"
"a: {}\n" "a: {}\n"
"b: {}\n" "b: {}\n"
@ -1303,9 +1272,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
"Clamp: {}\n" "Clamp: {}\n"
"Scale factor: {}\n" "Scale factor: {}\n"
"Dest: {}\n", "Dest: {}\n",
(data[0] - BPMEM_TEV_COLOR_ENV) / 2, tevin[cc.a], tevin[cc.b], tevin[cc.c], (data[0] - BPMEM_TEV_COLOR_ENV) / 2, cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op,
tevin[cc.d], tevbias[cc.bias], tevop[cc.op], no_yes[cc.clamp], no_yes[cc.clamp], cc.scale, cc.dest);
tevscale[cc.shift], tevout[cc.dest]);
break; break;
} }
@ -1329,13 +1297,6 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
SetRegName(BPMEM_TEV_ALPHA_ENV); SetRegName(BPMEM_TEV_ALPHA_ENV);
TevStageCombiner::AlphaCombiner ac; TevStageCombiner::AlphaCombiner ac;
ac.hex = cmddata; ac.hex = cmddata;
const char* tevin[] = {
"prev", "c0", "c1", "c2", "tex", "ras", "konst", "ZERO",
};
const char* tevbias[] = {"0", "+0.5", "-0.5", "compare"};
const char* tevop[] = {"add", "sub"};
const char* tevscale[] = {"1", "2", "4", "0.5"};
const char* tevout[] = {"prev", "c0", "c1", "c2"};
*desc = fmt::format("Tev stage: {}\n" *desc = fmt::format("Tev stage: {}\n"
"a: {}\n" "a: {}\n"
"b: {}\n" "b: {}\n"
@ -1348,9 +1309,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
"Dest: {}\n" "Dest: {}\n"
"Ras sel: {}\n" "Ras sel: {}\n"
"Tex sel: {}\n", "Tex sel: {}\n",
(data[0] - BPMEM_TEV_ALPHA_ENV) / 2, tevin[ac.a], tevin[ac.b], tevin[ac.c], (data[0] - BPMEM_TEV_ALPHA_ENV) / 2, ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op,
tevin[ac.d], tevbias[ac.bias], tevop[ac.op], no_yes[ac.clamp], no_yes[ac.clamp], ac.scale, ac.dest, ac.rswap.Value(), ac.tswap.Value());
tevscale[ac.shift], tevout[ac.dest], ac.rswap.Value(), ac.tswap.Value());
break; break;
} }
@ -1410,14 +1370,10 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
SetRegName(BPMEM_ALPHACOMPARE); SetRegName(BPMEM_ALPHACOMPARE);
AlphaTest test; AlphaTest test;
test.hex = cmddata; test.hex = cmddata;
const char* functions[] = {"NEVER", "LESS", "EQUAL", "LEQUAL",
"GREATER", "NEQUAL", "GEQUAL", "ALWAYS"};
const char* logic[] = {"AND", "OR", "XOR", "XNOR"};
*desc = fmt::format("Test 1: {} (ref: 0x{:02x})\n" *desc = fmt::format("Test 1: {} (ref: 0x{:02x})\n"
"Test 2: {} (ref: 0x{:02x})\n" "Test 2: {} (ref: 0x{:02x})\n"
"Logic: {}\n", "Logic: {}\n",
functions[test.comp0], test.ref0.Value(), functions[test.comp1], test.comp0, test.ref0.Value(), test.comp1, test.ref1.Value(), test.logic);
test.ref1.Value(), logic[test.logic]);
break; break;
} }

View file

@ -13,6 +13,9 @@ using float4 = std::array<float, 4>;
using uint4 = std::array<u32, 4>; using uint4 = std::array<u32, 4>;
using int4 = std::array<s32, 4>; using int4 = std::array<s32, 4>;
enum class SrcBlendFactor : u32;
enum class DstBlendFactor : u32;
struct PixelShaderConstants struct PixelShaderConstants
{ {
std::array<int4, 4> colors; std::array<int4, 4> colors;
@ -45,10 +48,10 @@ struct PixelShaderConstants
std::array<int4, 32> konst; // .rgba std::array<int4, 32> konst; // .rgba
// The following are used in ubershaders when using shader_framebuffer_fetch blending // The following are used in ubershaders when using shader_framebuffer_fetch blending
u32 blend_enable; u32 blend_enable;
u32 blend_src_factor; SrcBlendFactor blend_src_factor;
u32 blend_src_factor_alpha; SrcBlendFactor blend_src_factor_alpha;
u32 blend_dst_factor; DstBlendFactor blend_dst_factor;
u32 blend_dst_factor_alpha; DstBlendFactor blend_dst_factor_alpha;
u32 blend_subtract; u32 blend_subtract;
u32 blend_subtract_alpha; u32 blend_subtract_alpha;
}; };

View file

@ -174,14 +174,14 @@ PixelShaderUid GetPixelShaderUid()
pixel_shader_uid_data* const uid_data = out.GetUidData(); pixel_shader_uid_data* const uid_data = out.GetUidData();
uid_data->useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && uid_data->useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
uid_data->genMode_numindstages = bpmem.genMode.numindstages; uid_data->genMode_numindstages = bpmem.genMode.numindstages;
uid_data->genMode_numtevstages = bpmem.genMode.numtevstages; uid_data->genMode_numtevstages = bpmem.genMode.numtevstages;
uid_data->genMode_numtexgens = bpmem.genMode.numtexgens; uid_data->genMode_numtexgens = bpmem.genMode.numtexgens;
uid_data->bounding_box = g_ActiveConfig.bBBoxEnable && BoundingBox::IsEnabled(); uid_data->bounding_box = g_ActiveConfig.bBBoxEnable && BoundingBox::IsEnabled();
uid_data->rgba6_format = uid_data->rgba6_format =
bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor; bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor;
uid_data->dither = bpmem.blendmode.dither && uid_data->rgba6_format; uid_data->dither = bpmem.blendmode.dither && uid_data->rgba6_format;
uid_data->uint_output = bpmem.blendmode.UseLogicOp(); uid_data->uint_output = bpmem.blendmode.UseLogicOp();
@ -189,12 +189,13 @@ PixelShaderUid GetPixelShaderUid()
const bool forced_early_z = const bool forced_early_z =
bpmem.UseEarlyDepthTest() && bpmem.UseEarlyDepthTest() &&
(g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) (g_ActiveConfig.bFastDepthCalc ||
bpmem.alpha_test.TestResult() == AlphaTestResult::Undetermined)
// We can't allow early_ztest for zfreeze because depth is overridden per-pixel. // We can't allow early_ztest for zfreeze because depth is overridden per-pixel.
// This means it's impossible for zcomploc to be emulated on a zfrozen polygon. // This means it's impossible for zcomploc to be emulated on a zfrozen polygon.
&& !(bpmem.zmode.testenable && bpmem.genMode.zfreeze); && !(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
const bool per_pixel_depth = const bool per_pixel_depth =
(bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (bpmem.ztex2.op != ZTexOp::Disabled && bpmem.UseLateDepthTest()) ||
(!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) ||
(bpmem.zmode.testenable && bpmem.genMode.zfreeze); (bpmem.zmode.testenable && bpmem.genMode.zfreeze);
@ -253,10 +254,12 @@ PixelShaderUid GetPixelShaderUid()
uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF; uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF;
uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later
if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || if (cc.a == TevColorArg::RasAlpha || cc.a == TevColorArg::RasColor ||
cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || cc.b == TevColorArg::RasAlpha || cc.b == TevColorArg::RasColor ||
cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA || cc.c == TevColorArg::RasAlpha || cc.c == TevColorArg::RasColor ||
ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) cc.d == TevColorArg::RasAlpha || cc.d == TevColorArg::RasColor ||
ac.a == TevAlphaArg::RasAlpha || ac.b == TevAlphaArg::RasAlpha ||
ac.c == TevAlphaArg::RasAlpha || ac.d == TevAlphaArg::RasAlpha)
{ {
const int i = bpmem.combiners[n].alphaC.rswap; const int i = bpmem.combiners[n].alphaC.rswap;
uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1; uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1;
@ -277,9 +280,9 @@ PixelShaderUid GetPixelShaderUid()
uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1); uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1);
} }
if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || if (cc.a == TevColorArg::Konst || cc.b == TevColorArg::Konst || cc.c == TevColorArg::Konst ||
cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst ||
ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst)
{ {
uid_data->stagehash[n].tevksel_kc = bpmem.tevksel[n / 2].getKC(n & 1); uid_data->stagehash[n].tevksel_kc = bpmem.tevksel[n / 2].getKC(n & 1);
uid_data->stagehash[n].tevksel_ka = bpmem.tevksel[n / 2].getKA(n & 1); uid_data->stagehash[n].tevksel_ka = bpmem.tevksel[n / 2].getKA(n & 1);
@ -291,15 +294,14 @@ PixelShaderUid GetPixelShaderUid()
sizeof(*uid_data) : sizeof(*uid_data) :
MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]); MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]);
AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); uid_data->Pretest = bpmem.alpha_test.TestResult();
uid_data->Pretest = Pretest;
uid_data->late_ztest = bpmem.UseLateDepthTest(); uid_data->late_ztest = bpmem.UseLateDepthTest();
// NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled
// (in this case we need to write a depth value if depth test passes regardless of the alpha // (in this case we need to write a depth value if depth test passes regardless of the alpha
// testing result) // testing result)
if (uid_data->Pretest == AlphaTest::UNDETERMINED || if (uid_data->Pretest == AlphaTestResult::Undetermined ||
(uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest)) (uid_data->Pretest == AlphaTestResult::Fail && uid_data->late_ztest))
{ {
uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0; uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0;
uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1; uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1;
@ -320,7 +322,7 @@ PixelShaderUid GetPixelShaderUid()
uid_data->zfreeze = bpmem.genMode.zfreeze; uid_data->zfreeze = bpmem.genMode.zfreeze;
uid_data->ztex_op = bpmem.ztex2.op; uid_data->ztex_op = bpmem.ztex2.op;
uid_data->early_ztest = bpmem.UseEarlyDepthTest(); uid_data->early_ztest = bpmem.UseEarlyDepthTest();
uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel;
uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel;
uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj; uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj;
uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled; uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled;
@ -517,8 +519,8 @@ void UpdateBoundingBox(float2 rawpos) {{
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n, static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
APIType api_type, bool stereo); APIType api_type, bool stereo);
static void WriteTevRegular(ShaderCode& out, std::string_view components, int bias, int op, static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
int clamp, int shift, bool alpha); bool clamp, TevScale scale, bool alpha);
static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap, static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap,
int texmap, bool stereo, APIType api_type); int texmap, bool stereo, APIType api_type);
static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type, static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type,
@ -826,13 +828,13 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
TevStageCombiner::AlphaCombiner last_ac; TevStageCombiner::AlphaCombiner last_ac;
last_cc.hex = uid_data->stagehash[uid_data->genMode_numtevstages].cc; last_cc.hex = uid_data->stagehash[uid_data->genMode_numtevstages].cc;
last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac; last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac;
if (last_cc.dest != 0) if (last_cc.dest != TevOutput::Prev)
{ {
out.Write("\tprev.rgb = {};\n", tev_c_output_table[last_cc.dest]); out.Write("\tprev.rgb = {};\n", tev_c_output_table[u32(last_cc.dest.Value())]);
} }
if (last_ac.dest != 0) if (last_ac.dest != TevOutput::Prev)
{ {
out.Write("\tprev.a = {};\n", tev_a_output_table[last_ac.dest]); out.Write("\tprev.a = {};\n", tev_a_output_table[u32(last_ac.dest.Value())]);
} }
} }
out.Write("\tprev = prev & 255;\n"); out.Write("\tprev = prev & 255;\n");
@ -840,8 +842,8 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
// NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled
// (in this case we need to write a depth value if depth test passes regardless of the alpha // (in this case we need to write a depth value if depth test passes regardless of the alpha
// testing result) // testing result)
if (uid_data->Pretest == AlphaTest::UNDETERMINED || if (uid_data->Pretest == AlphaTestResult::Undetermined ||
(uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest)) (uid_data->Pretest == AlphaTestResult::Fail && uid_data->late_ztest))
{ {
WriteAlphaTest(out, uid_data, api_type, uid_data->per_pixel_depth, WriteAlphaTest(out, uid_data, api_type, uid_data->per_pixel_depth,
use_dual_source || use_shader_blend); use_dual_source || use_shader_blend);
@ -884,7 +886,7 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
// depth texture can safely be ignored if the result won't be written to the depth buffer // depth texture can safely be ignored if the result won't be written to the depth buffer
// (early_ztest) and isn't used for fog either // (early_ztest) and isn't used for fog either
const bool skip_ztexture = !uid_data->per_pixel_depth && !uid_data->fog_fsel; const bool skip_ztexture = !uid_data->per_pixel_depth && uid_data->fog_fsel == FogType::Off;
// Note: z-textures are not written to depth buffer if early depth test is used // Note: z-textures are not written to depth buffer if early depth test is used
if (uid_data->per_pixel_depth && uid_data->early_ztest) if (uid_data->per_pixel_depth && uid_data->early_ztest)
@ -898,13 +900,13 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
// Note: depth texture output is only written to depth buffer if late depth test is used // Note: depth texture output is only written to depth buffer if late depth test is used
// theoretical final depth value is used for fog calculation, though, so we have to emulate // theoretical final depth value is used for fog calculation, though, so we have to emulate
// ztextures anyway // ztextures anyway
if (uid_data->ztex_op != ZTEXTURE_DISABLE && !skip_ztexture) if (uid_data->ztex_op != ZTexOp::Disabled && !skip_ztexture)
{ {
// use the texture input of the last texture stage (textemp), hopefully this has been read and // use the texture input of the last texture stage (textemp), hopefully this has been read and
// is in correct format... // is in correct format...
out.SetConstantsUsed(C_ZBIAS, C_ZBIAS + 1); out.SetConstantsUsed(C_ZBIAS, C_ZBIAS + 1);
out.Write("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w {};\n", out.Write("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w {};\n",
(uid_data->ztex_op == ZTEXTURE_ADD) ? "+ zCoord" : ""); (uid_data->ztex_op == ZTexOp::Add) ? "+ zCoord" : "");
out.Write("\tzCoord = zCoord & 0xFFFFFF;\n"); out.Write("\tzCoord = zCoord & 0xFFFFFF;\n");
} }
@ -963,7 +965,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
// Perform the indirect op on the incoming regular coordinates // Perform the indirect op on the incoming regular coordinates
// using iindtex{} as the offset coords // using iindtex{} as the offset coords
if (tevind.bs != ITBA_OFF) if (tevind.bs != IndTexBumpAlpha::Off)
{ {
static constexpr std::array<const char*, 4> tev_ind_alpha_sel{ static constexpr std::array<const char*, 4> tev_ind_alpha_sel{
"", "",
@ -980,8 +982,9 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
"248", "248",
}; };
out.Write("alphabump = iindtex{}.{} & {};\n", tevind.bt.Value(), tev_ind_alpha_sel[tevind.bs], out.Write("alphabump = iindtex{}.{} & {};\n", tevind.bt.Value(),
tev_ind_alpha_mask[tevind.fmt]); tev_ind_alpha_sel[u32(tevind.bs.Value())],
tev_ind_alpha_mask[u32(tevind.fmt.Value())]);
} }
else else
{ {
@ -998,7 +1001,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
"7", "7",
}; };
out.Write("\tint3 iindtevcrd{} = iindtex{} & {};\n", n, tevind.bt.Value(), out.Write("\tint3 iindtevcrd{} = iindtex{} & {};\n", n, tevind.bt.Value(),
tev_ind_fmt_mask[tevind.fmt]); tev_ind_fmt_mask[u32(tevind.fmt.Value())]);
// bias - TODO: Check if this needs to be this complicated... // bias - TODO: Check if this needs to be this complicated...
// indexed by bias // indexed by bias
@ -1014,21 +1017,25 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
"1", "1",
}; };
if (tevind.bias == ITB_S || tevind.bias == ITB_T || tevind.bias == ITB_U) if (tevind.bias == IndTexBias::S || tevind.bias == IndTexBias::T ||
tevind.bias == IndTexBias::U)
{ {
out.Write("\tiindtevcrd{}.{} += int({});\n", n, tev_ind_bias_field[tevind.bias], out.Write("\tiindtevcrd{}.{} += int({});\n", n,
tev_ind_bias_add[tevind.fmt]); tev_ind_bias_field[u32(tevind.bias.Value())],
tev_ind_bias_add[u32(tevind.fmt.Value())]);
} }
else if (tevind.bias == ITB_ST || tevind.bias == ITB_SU || tevind.bias == ITB_TU) else if (tevind.bias == IndTexBias::ST || tevind.bias == IndTexBias::SU ||
tevind.bias == IndTexBias::TU_)
{ {
out.Write("\tiindtevcrd{}.{} += int2({}, {});\n", n, tev_ind_bias_field[tevind.bias], out.Write("\tiindtevcrd{0}.{1} += int2({2}, {2});\n", n,
tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt]); tev_ind_bias_field[u32(tevind.bias.Value())],
tev_ind_bias_add[u32(tevind.fmt.Value())]);
} }
else if (tevind.bias == ITB_STU) else if (tevind.bias == IndTexBias::STU)
{ {
out.Write("\tiindtevcrd{}.{} += int3({}, {}, {});\n", n, tev_ind_bias_field[tevind.bias], out.Write("\tiindtevcrd{0}.{1} += int3({2}, {2}, {2});\n", n,
tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt], tev_ind_bias_field[u32(tevind.bias.Value())],
tev_ind_bias_add[tevind.fmt]); tev_ind_bias_add[u32(tevind.fmt.Value())]);
} }
// multiply by offset matrix and scale - calculations are likely to overflow badly, // multiply by offset matrix and scale - calculations are likely to overflow badly,
@ -1122,33 +1129,33 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
}; };
// wrap S // wrap S
if (tevind.sw == ITW_OFF) if (tevind.sw == IndTexWrap::ITW_OFF)
{ {
out.Write("\twrappedcoord.x = fixpoint_uv{}.x;\n", texcoord); out.Write("\twrappedcoord.x = fixpoint_uv{}.x;\n", texcoord);
} }
else if (tevind.sw == ITW_0) else if (tevind.sw == IndTexWrap::ITW_0)
{ {
out.Write("\twrappedcoord.x = 0;\n"); out.Write("\twrappedcoord.x = 0;\n");
} }
else else
{ {
out.Write("\twrappedcoord.x = fixpoint_uv{}.x & ({} - 1);\n", texcoord, out.Write("\twrappedcoord.x = fixpoint_uv{}.x & ({} - 1);\n", texcoord,
tev_ind_wrap_start[tevind.sw]); tev_ind_wrap_start[u32(tevind.sw.Value())]);
} }
// wrap T // wrap T
if (tevind.tw == ITW_OFF) if (tevind.tw == IndTexWrap::ITW_OFF)
{ {
out.Write("\twrappedcoord.y = fixpoint_uv{}.y;\n", texcoord); out.Write("\twrappedcoord.y = fixpoint_uv{}.y;\n", texcoord);
} }
else if (tevind.tw == ITW_0) else if (tevind.tw == IndTexWrap::ITW_0)
{ {
out.Write("\twrappedcoord.y = 0;\n"); out.Write("\twrappedcoord.y = 0;\n");
} }
else else
{ {
out.Write("\twrappedcoord.y = fixpoint_uv{}.y & ({} - 1);\n", texcoord, out.Write("\twrappedcoord.y = fixpoint_uv{}.y & ({} - 1);\n", texcoord,
tev_ind_wrap_start[tevind.tw]); tev_ind_wrap_start[u32(tevind.tw.Value())]);
} }
if (tevind.fb_addprev) // add previous tevcoord if (tevind.fb_addprev) // add previous tevcoord
@ -1165,10 +1172,12 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
cc.hex = stage.cc; cc.hex = stage.cc;
ac.hex = stage.ac; ac.hex = stage.ac;
if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || if (cc.a == TevColorArg::RasAlpha || cc.a == TevColorArg::RasColor ||
cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || cc.b == TevColorArg::RasAlpha || cc.b == TevColorArg::RasColor ||
cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA || cc.c == TevColorArg::RasAlpha || cc.c == TevColorArg::RasColor ||
ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) cc.d == TevColorArg::RasAlpha || cc.d == TevColorArg::RasColor ||
ac.a == TevAlphaArg::RasAlpha || ac.b == TevAlphaArg::RasAlpha ||
ac.c == TevAlphaArg::RasAlpha || ac.d == TevAlphaArg::RasAlpha)
{ {
// Generate swizzle string to represent the Ras color channel swapping // Generate swizzle string to represent the Ras color channel swapping
const char rasswap[5] = { const char rasswap[5] = {
@ -1179,7 +1188,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
'\0', '\0',
}; };
out.Write("\trastemp = {}.{};\n", tev_ras_table[stage.tevorders_colorchan], rasswap); out.Write("\trastemp = {}.{};\n", tev_ras_table[u32(stage.tevorders_colorchan)], rasswap);
} }
if (stage.tevorders_enable) if (stage.tevorders_enable)
@ -1209,72 +1218,73 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
out.Write("\ttextemp = int4(255, 255, 255, 255);\n"); out.Write("\ttextemp = int4(255, 255, 255, 255);\n");
} }
if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || if (cc.a == TevColorArg::Konst || cc.b == TevColorArg::Konst || cc.c == TevColorArg::Konst ||
cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst ||
ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst)
{ {
out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[stage.tevksel_kc], out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[u32(stage.tevksel_kc)],
tev_ksel_table_a[stage.tevksel_ka]); tev_ksel_table_a[u32(stage.tevksel_ka)]);
if (stage.tevksel_kc > 7) if (u32(stage.tevksel_kc) > 7)
{ {
out.SetConstantsUsed(C_KCOLORS + ((stage.tevksel_kc - 0xc) % 4), out.SetConstantsUsed(C_KCOLORS + ((u32(stage.tevksel_kc) - 0xc) % 4),
C_KCOLORS + ((stage.tevksel_kc - 0xc) % 4)); C_KCOLORS + ((u32(stage.tevksel_kc) - 0xc) % 4));
} }
if (stage.tevksel_ka > 7) if (u32(stage.tevksel_ka) > 7)
{ {
out.SetConstantsUsed(C_KCOLORS + ((stage.tevksel_ka - 0xc) % 4), out.SetConstantsUsed(C_KCOLORS + ((u32(stage.tevksel_ka) - 0xc) % 4),
C_KCOLORS + ((stage.tevksel_ka - 0xc) % 4)); C_KCOLORS + ((u32(stage.tevksel_ka) - 0xc) % 4));
} }
} }
if (cc.d == TEVCOLORARG_C0 || cc.d == TEVCOLORARG_A0 || ac.d == TEVALPHAARG_A0) if (cc.d == TevColorArg::Color0 || cc.d == TevColorArg::Alpha0 || ac.d == TevAlphaArg::Alpha0)
out.SetConstantsUsed(C_COLORS + 1, C_COLORS + 1); out.SetConstantsUsed(C_COLORS + 1, C_COLORS + 1);
if (cc.d == TEVCOLORARG_C1 || cc.d == TEVCOLORARG_A1 || ac.d == TEVALPHAARG_A1) if (cc.d == TevColorArg::Color1 || cc.d == TevColorArg::Alpha1 || ac.d == TevAlphaArg::Alpha1)
out.SetConstantsUsed(C_COLORS + 2, C_COLORS + 2); out.SetConstantsUsed(C_COLORS + 2, C_COLORS + 2);
if (cc.d == TEVCOLORARG_C2 || cc.d == TEVCOLORARG_A2 || ac.d == TEVALPHAARG_A2) if (cc.d == TevColorArg::Color2 || cc.d == TevColorArg::Alpha2 || ac.d == TevAlphaArg::Alpha2)
out.SetConstantsUsed(C_COLORS + 3, C_COLORS + 3); out.SetConstantsUsed(C_COLORS + 3, C_COLORS + 3);
if (cc.dest >= GX_TEVREG0) if (cc.dest >= TevOutput::Color0)
out.SetConstantsUsed(C_COLORS + cc.dest, C_COLORS + cc.dest); out.SetConstantsUsed(C_COLORS + u32(cc.dest.Value()), C_COLORS + u32(cc.dest.Value()));
if (ac.dest >= GX_TEVREG0) if (ac.dest >= TevOutput::Color0)
out.SetConstantsUsed(C_COLORS + ac.dest, C_COLORS + ac.dest); out.SetConstantsUsed(C_COLORS + u32(ac.dest.Value()), C_COLORS + u32(ac.dest.Value()));
out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.a], out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n",
tev_a_input_table[ac.a]); tev_c_input_table[u32(cc.a.Value())], tev_a_input_table[u32(ac.a.Value())]);
out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.b], out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n",
tev_a_input_table[ac.b]); tev_c_input_table[u32(cc.b.Value())], tev_a_input_table[u32(ac.b.Value())]);
out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.c], out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n",
tev_a_input_table[ac.c]); tev_c_input_table[u32(cc.c.Value())], tev_a_input_table[u32(ac.c.Value())]);
out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[cc.d], tev_a_input_table[ac.d]); out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[u32(cc.d.Value())],
tev_a_input_table[u32(ac.d.Value())]);
out.Write("\t// color combine\n"); out.Write("\t// color combine\n");
out.Write("\t{} = clamp(", tev_c_output_table[cc.dest]); out.Write("\t{} = clamp(", tev_c_output_table[u32(cc.dest.Value())]);
if (cc.bias != TEVBIAS_COMPARE) if (cc.bias != TevBias::Compare)
{ {
WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.shift, false); WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.scale, false);
} }
else else
{ {
static constexpr std::array<const char*, 8> function_table{ static constexpr std::array<const char*, 8> function_table{
"((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_GT "((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TevCompareMode::R8, GT
"((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_EQ "((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // R8, TevComparison::EQ
"((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : "
"int3(0,0,0))", // TEVCMP_GR16_GT "int3(0,0,0))", // GR16, GT
"((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : "
"int3(0,0,0))", // TEVCMP_GR16_EQ "int3(0,0,0))", // GR16, EQ
"((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : " "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : "
"int3(0,0,0))", // TEVCMP_BGR24_GT "int3(0,0,0))", // BGR24, GT
"((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : " "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : "
"int3(0,0,0))", // TEVCMP_BGR24_EQ "int3(0,0,0))", // BGR24, EQ
"(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // TEVCMP_RGB8_GT "(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // RGB8, GT
"((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // TEVCMP_RGB8_EQ "((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // RGB8, EQ
}; };
const u32 mode = (cc.shift << 1) | cc.op; const u32 mode = (u32(cc.compare_mode.Value()) << 1) | u32(cc.comparison.Value());
out.Write(" tevin_d.rgb + "); out.Write(" tevin_d.rgb + ");
out.Write("{}", function_table[mode]); out.Write("{}", function_table[mode]);
} }
@ -1285,25 +1295,25 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
out.Write(";\n"); out.Write(";\n");
out.Write("\t// alpha combine\n"); out.Write("\t// alpha combine\n");
out.Write("\t{} = clamp(", tev_a_output_table[ac.dest]); out.Write("\t{} = clamp(", tev_a_output_table[u32(ac.dest.Value())]);
if (ac.bias != TEVBIAS_COMPARE) if (ac.bias != TevBias::Compare)
{ {
WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.shift, true); WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.scale, true);
} }
else else
{ {
static constexpr std::array<const char*, 8> function_table{ static constexpr std::array<const char*, 8> function_table{
"((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_GT "((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TevCompareMode::R8, GT
"((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_EQ "((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // R8, TevComparison::EQ
"((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_GT "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16, GT
"((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_EQ "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16, EQ
"((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_GT "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24, GT
"((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_EQ "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24, EQ
"((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // TEVCMP_A8_GT "((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // A8, GT
"((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // TEVCMP_A8_EQ "((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // A8, EQ
}; };
const u32 mode = (ac.shift << 1) | ac.op; const u32 mode = (u32(ac.compare_mode.Value()) << 1) | u32(ac.comparison.Value());
out.Write(" tevin_d.a + "); out.Write(" tevin_d.a + ");
out.Write("{}", function_table[mode]); out.Write("{}", function_table[mode]);
} }
@ -1315,24 +1325,24 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
out.Write(";\n"); out.Write(";\n");
} }
static void WriteTevRegular(ShaderCode& out, std::string_view components, int bias, int op, static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
int clamp, int shift, bool alpha) bool clamp, TevScale scale, bool alpha)
{ {
static constexpr std::array<const char*, 4> tev_scale_table_left{ static constexpr std::array<const char*, 4> tev_scale_table_left{
"", // SCALE_1 "", // Scale1
" << 1", // SCALE_2 " << 1", // Scale2
" << 2", // SCALE_4 " << 2", // Scale4
"", // DIVIDE_2 "", // Divide2
}; };
static constexpr std::array<const char*, 4> tev_scale_table_right{ static constexpr std::array<const char*, 4> tev_scale_table_right{
"", // SCALE_1 "", // Scale1
"", // SCALE_2 "", // Scale2
"", // SCALE_4 "", // Scale4
" >> 1", // DIVIDE_2 " >> 1", // Divide2
}; };
// indexed by 2*op+(shift==3) // indexed by 2*op+(scale==Divide2)
static constexpr std::array<const char*, 4> tev_lerp_bias{ static constexpr std::array<const char*, 4> tev_lerp_bias{
"", "",
" + 128", " + 128",
@ -1341,15 +1351,15 @@ static void WriteTevRegular(ShaderCode& out, std::string_view components, int bi
}; };
static constexpr std::array<const char*, 4> tev_bias_table{ static constexpr std::array<const char*, 4> tev_bias_table{
"", // ZERO, "", // Zero,
" + 128", // ADDHALF, " + 128", // AddHalf,
" - 128", // SUBHALF, " - 128", // SubHalf,
"", "",
}; };
static constexpr std::array<char, 2> tev_op_table{ static constexpr std::array<char, 2> tev_op_table{
'+', // TEVOP_ADD = 0, '+', // TevOp::Add = 0,
'-', // TEVOP_SUB = 1, '-', // TevOp::Sub = 1,
}; };
// Regular TEV stage: (d + bias + lerp(a,b,c)) * scale // Regular TEV stage: (d + bias + lerp(a,b,c)) * scale
@ -1357,12 +1367,14 @@ static void WriteTevRegular(ShaderCode& out, std::string_view components, int bi
// - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255 // - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255
// - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy // - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy
// - a rounding bias is added before dividing by 256 // - a rounding bias is added before dividing by 256
out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[bias], tev_scale_table_left[shift]); out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[u32(bias)],
out.Write(" {} ", tev_op_table[op]); tev_scale_table_left[u32(scale)]);
out.Write(" {} ", tev_op_table[u32(op)]);
out.Write("(((((tevin_a.{}<<8) + (tevin_b.{}-tevin_a.{})*(tevin_c.{}+(tevin_c.{}>>7))){}){})>>8)", out.Write("(((((tevin_a.{}<<8) + (tevin_b.{}-tevin_a.{})*(tevin_c.{}+(tevin_c.{}>>7))){}){})>>8)",
components, components, components, components, components, tev_scale_table_left[shift], components, components, components, components, components,
tev_lerp_bias[2 * op + ((shift == 3) == alpha)]); tev_scale_table_left[u32(scale)],
out.Write("){}", tev_scale_table_right[shift]); tev_lerp_bias[2 * u32(op) + ((scale == TevScale::Divide2) == alpha)]);
out.Write("){}", tev_scale_table_right[u32(scale)]);
} }
static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap, static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap,
@ -1384,14 +1396,14 @@ static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::stri
} }
constexpr std::array<const char*, 8> tev_alpha_funcs_table{ constexpr std::array<const char*, 8> tev_alpha_funcs_table{
"(false)", // NEVER "(false)", // CompareMode::Never
"(prev.a < {})", // LESS "(prev.a < {})", // CompareMode::Less
"(prev.a == {})", // EQUAL "(prev.a == {})", // CompareMode::Equal
"(prev.a <= {})", // LEQUAL "(prev.a <= {})", // CompareMode::LEqual
"(prev.a > {})", // GREATER "(prev.a > {})", // CompareMode::Greater
"(prev.a != {})", // NEQUAL "(prev.a != {})", // CompareMode::NEqual
"(prev.a >= {})", // GEQUAL "(prev.a >= {})", // CompareMode::GEqual
"(true)" // ALWAYS "(true)" // CompareMode::Always
}; };
constexpr std::array<const char*, 4> tev_alpha_funclogic_table{ constexpr std::array<const char*, 4> tev_alpha_funclogic_table{
@ -1409,12 +1421,12 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat
I_ALPHA ".g", I_ALPHA ".g",
}; };
const auto write_alpha_func = [&out](int index, std::string_view ref) { const auto write_alpha_func = [&out](CompareMode mode, std::string_view ref) {
const bool has_no_arguments = index == 0 || index == tev_alpha_funcs_table.size() - 1; const bool has_no_arguments = mode == CompareMode::Never || mode == CompareMode::Always;
if (has_no_arguments) if (has_no_arguments)
out.Write("{}", tev_alpha_funcs_table[index]); out.Write("{}", tev_alpha_funcs_table[u32(mode)]);
else else
out.Write(tev_alpha_funcs_table[index], ref); out.Write(tev_alpha_funcs_table[u32(mode)], ref);
}; };
out.SetConstantsUsed(C_ALPHA, C_ALPHA); out.SetConstantsUsed(C_ALPHA, C_ALPHA);
@ -1425,15 +1437,13 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat
out.Write("\tif(!( "); out.Write("\tif(!( ");
// Lookup the first component from the alpha function table // Lookup the first component from the alpha function table
const int comp0_index = uid_data->alpha_test_comp0; write_alpha_func(uid_data->alpha_test_comp0, alpha_ref[0]);
write_alpha_func(comp0_index, alpha_ref[0]);
// Lookup the logic op // Lookup the logic op
out.Write("{}", tev_alpha_funclogic_table[uid_data->alpha_test_logic]); out.Write("{}", tev_alpha_funclogic_table[u32(uid_data->alpha_test_logic)]);
// Lookup the second component from the alpha function table // Lookup the second component from the alpha function table
const int comp1_index = uid_data->alpha_test_comp1; write_alpha_func(uid_data->alpha_test_comp1, alpha_ref[1]);
write_alpha_func(comp1_index, alpha_ref[1]);
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_NEGATED_BOOLEAN)) if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_NEGATED_BOOLEAN))
out.Write(") == false) {{\n"); out.Write(") == false) {{\n");
@ -1473,13 +1483,13 @@ constexpr std::array<const char*, 8> tev_fog_funcs_table{
static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data) static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data)
{ {
if (uid_data->fog_fsel == 0) if (uid_data->fog_fsel == FogType::Off)
return; // no Fog return; // no Fog
out.SetConstantsUsed(C_FOGCOLOR, C_FOGCOLOR); out.SetConstantsUsed(C_FOGCOLOR, C_FOGCOLOR);
out.SetConstantsUsed(C_FOGI, C_FOGI); out.SetConstantsUsed(C_FOGI, C_FOGI);
out.SetConstantsUsed(C_FOGF, C_FOGF + 1); out.SetConstantsUsed(C_FOGF, C_FOGF + 1);
if (uid_data->fog_proj == 0) if (uid_data->fog_proj == FogProjection::Perspective)
{ {
// perspective // perspective
// ze = A/(B - (Zs >> B_SHF) // ze = A/(B - (Zs >> B_SHF)
@ -1515,14 +1525,14 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data)
out.Write("\tfloat fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n"); out.Write("\tfloat fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n");
if (uid_data->fog_fsel > 3) if (uid_data->fog_fsel >= FogType::Exp)
{ {
out.Write("{}", tev_fog_funcs_table[uid_data->fog_fsel]); out.Write("{}", tev_fog_funcs_table[u32(uid_data->fog_fsel)]);
} }
else else
{ {
if (uid_data->fog_fsel != 2) if (uid_data->fog_fsel != FogType::Linear)
WARN_LOG_FMT(VIDEO, "Unknown Fog Type! {:08x}", uid_data->fog_fsel); WARN_LOG_FMT(VIDEO, "Unknown Fog Type! {}", uid_data->fog_fsel);
} }
out.Write("\tint ifog = iround(fog * 256.0);\n"); out.Write("\tint ifog = iround(fog * 256.0);\n");
@ -1611,11 +1621,13 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data)
"1.0 - initial_ocol0.a;", // INVDSTALPHA "1.0 - initial_ocol0.a;", // INVDSTALPHA
}; };
out.Write("\tfloat4 blend_src;\n"); out.Write("\tfloat4 blend_src;\n");
out.Write("\tblend_src.rgb = {}\n", blend_src_factor[uid_data->blend_src_factor]); out.Write("\tblend_src.rgb = {}\n", blend_src_factor[u32(uid_data->blend_src_factor)]);
out.Write("\tblend_src.a = {}\n", blend_src_factor_alpha[uid_data->blend_src_factor_alpha]); out.Write("\tblend_src.a = {}\n",
blend_src_factor_alpha[u32(uid_data->blend_src_factor_alpha)]);
out.Write("\tfloat4 blend_dst;\n"); out.Write("\tfloat4 blend_dst;\n");
out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[uid_data->blend_dst_factor]); out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[u32(uid_data->blend_dst_factor)]);
out.Write("\tblend_dst.a = {}\n", blend_dst_factor_alpha[uid_data->blend_dst_factor_alpha]); out.Write("\tblend_dst.a = {}\n",
blend_dst_factor_alpha[u32(uid_data->blend_dst_factor_alpha)]);
out.Write("\tfloat4 blend_result;\n"); out.Write("\tfloat4 blend_result;\n");
if (uid_data->blend_subtract) if (uid_data->blend_subtract)

View file

@ -9,6 +9,15 @@
#include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/ShaderGenCommon.h"
enum class APIType; enum class APIType;
enum class AlphaTestResult;
enum class SrcBlendFactor : u32;
enum class DstBlendFactor : u32;
enum class CompareMode : u32;
enum class AlphaTestOp : u32;
enum class RasColorChan : u32;
enum class KonstSel : u32;
enum class FogProjection : u32;
enum class FogType : u32;
#pragma pack(1) #pragma pack(1)
struct pixel_shader_uid_data struct pixel_shader_uid_data
@ -19,18 +28,18 @@ struct pixel_shader_uid_data
u32 NumValues() const { return num_values; } u32 NumValues() const { return num_values; }
u32 pad0 : 4; u32 pad0 : 4;
u32 useDstAlpha : 1; u32 useDstAlpha : 1;
u32 Pretest : 2; AlphaTestResult Pretest : 2;
u32 nIndirectStagesUsed : 4; u32 nIndirectStagesUsed : 4;
u32 genMode_numtexgens : 4; u32 genMode_numtexgens : 4;
u32 genMode_numtevstages : 4; u32 genMode_numtevstages : 4;
u32 genMode_numindstages : 3; u32 genMode_numindstages : 3;
u32 alpha_test_comp0 : 3; CompareMode alpha_test_comp0 : 3;
u32 alpha_test_comp1 : 3; CompareMode alpha_test_comp1 : 3;
u32 alpha_test_logic : 2; AlphaTestOp alpha_test_logic : 2;
u32 alpha_test_use_zcomploc_hack : 1; u32 alpha_test_use_zcomploc_hack : 1;
u32 fog_proj : 1; FogProjection fog_proj : 1;
u32 fog_fsel : 3; FogType fog_fsel : 3;
u32 fog_RangeBaseEnabled : 1; u32 fog_RangeBaseEnabled : 1;
u32 ztex_op : 2; u32 ztex_op : 2;
u32 per_pixel_depth : 1; u32 per_pixel_depth : 1;
@ -44,10 +53,10 @@ struct pixel_shader_uid_data
u32 dither : 1; u32 dither : 1;
u32 uint_output : 1; u32 uint_output : 1;
u32 blend_enable : 1; // Only used with shader_framebuffer_fetch blend u32 blend_enable : 1; // Only used with shader_framebuffer_fetch blend
u32 blend_src_factor : 3; // Only used with shader_framebuffer_fetch blend SrcBlendFactor blend_src_factor : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_src_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend SrcBlendFactor blend_src_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_dst_factor : 3; // Only used with shader_framebuffer_fetch blend DstBlendFactor blend_dst_factor : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_dst_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend DstBlendFactor blend_dst_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend
u32 blend_subtract : 1; // Only used with shader_framebuffer_fetch blend u32 blend_subtract : 1; // Only used with shader_framebuffer_fetch blend
u32 blend_subtract_alpha : 1; // Only used with shader_framebuffer_fetch blend u32 blend_subtract_alpha : 1; // Only used with shader_framebuffer_fetch blend
@ -136,7 +145,7 @@ struct pixel_shader_uid_data
u32 tevorders_texmap : 3; u32 tevorders_texmap : 3;
u32 tevorders_texcoord : 3; u32 tevorders_texcoord : 3;
u32 tevorders_enable : 1; u32 tevorders_enable : 1;
u32 tevorders_colorchan : 3; RasColorChan tevorders_colorchan : 3;
u32 pad1 : 6; u32 pad1 : 6;
// TODO: Clean up the swapXY mess // TODO: Clean up the swapXY mess
@ -152,8 +161,8 @@ struct pixel_shader_uid_data
u32 tevksel_swap2c : 2; u32 tevksel_swap2c : 2;
u32 tevksel_swap1d : 2; u32 tevksel_swap1d : 2;
u32 tevksel_swap2d : 2; u32 tevksel_swap2d : 2;
u32 tevksel_kc : 5; KonstSel tevksel_kc : 5;
u32 tevksel_ka : 5; KonstSel tevksel_ka : 5;
u32 pad3 : 14; u32 pad3 : 14;
} stagehash[16]; } stagehash[16];

View file

@ -182,7 +182,7 @@ void PixelShaderManager::SetConstants()
// Destination alpha is only enabled if alpha writes are enabled. Force entire uniform to zero // Destination alpha is only enabled if alpha writes are enabled. Force entire uniform to zero
// when disabled. // when disabled.
u32 dstalpha = bpmem.blendmode.alphaupdate && bpmem.dstalpha.enable && u32 dstalpha = bpmem.blendmode.alphaupdate && bpmem.dstalpha.enable &&
bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 ? bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 ?
bpmem.dstalpha.hex : bpmem.dstalpha.hex :
0; 0;
@ -270,7 +270,7 @@ void PixelShaderManager::SetAlphaTestChanged()
// TODO: we could optimize this further and check the actual constants, // TODO: we could optimize this further and check the actual constants,
// i.e. "a <= 0" and "a >= 255" will always pass. // i.e. "a <= 0" and "a >= 255" will always pass.
u32 alpha_test = u32 alpha_test =
bpmem.alpha_test.TestResult() != AlphaTest::PASS ? bpmem.alpha_test.hex | 1 << 31 : 0; bpmem.alpha_test.TestResult() != AlphaTestResult::Pass ? bpmem.alpha_test.hex | 1 << 31 : 0;
if (constants.alphaTest != alpha_test) if (constants.alphaTest != alpha_test)
{ {
constants.alphaTest = alpha_test; constants.alphaTest = alpha_test;
@ -362,25 +362,26 @@ void PixelShaderManager::SetZTextureTypeChanged()
{ {
switch (bpmem.ztex2.type) switch (bpmem.ztex2.type)
{ {
case TEV_ZTEX_TYPE_U8: case ZTexFormat::U8:
constants.zbias[0][0] = 0; constants.zbias[0][0] = 0;
constants.zbias[0][1] = 0; constants.zbias[0][1] = 0;
constants.zbias[0][2] = 0; constants.zbias[0][2] = 0;
constants.zbias[0][3] = 1; constants.zbias[0][3] = 1;
break; break;
case TEV_ZTEX_TYPE_U16: case ZTexFormat::U16:
constants.zbias[0][0] = 1; constants.zbias[0][0] = 1;
constants.zbias[0][1] = 0; constants.zbias[0][1] = 0;
constants.zbias[0][2] = 0; constants.zbias[0][2] = 0;
constants.zbias[0][3] = 256; constants.zbias[0][3] = 256;
break; break;
case TEV_ZTEX_TYPE_U24: case ZTexFormat::U24:
constants.zbias[0][0] = 65536; constants.zbias[0][0] = 65536;
constants.zbias[0][1] = 256; constants.zbias[0][1] = 256;
constants.zbias[0][2] = 1; constants.zbias[0][2] = 1;
constants.zbias[0][3] = 0; constants.zbias[0][3] = 0;
break; break;
default: default:
PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type);
break; break;
} }
dirty = true; dirty = true;
@ -457,7 +458,8 @@ void PixelShaderManager::SetZModeControl()
{ {
u32 late_ztest = bpmem.UseLateDepthTest(); u32 late_ztest = bpmem.UseLateDepthTest();
u32 rgba6_format = u32 rgba6_format =
(bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ? 1 : (bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ?
1 :
0; 0;
u32 dither = rgba6_format && bpmem.blendmode.dither; u32 dither = rgba6_format && bpmem.blendmode.dither;
if (constants.late_ztest != late_ztest || constants.rgba6_format != rgba6_format || if (constants.late_ztest != late_ztest || constants.rgba6_format != rgba6_format ||

View file

@ -171,7 +171,7 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
bool Renderer::EFBHasAlphaChannel() const bool Renderer::EFBHasAlphaChannel() const
{ {
return m_prev_efb_format == PEControl::RGBA6_Z24; return m_prev_efb_format == PixelFormat::RGBA6_Z24;
} }
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable, void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
@ -197,15 +197,15 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
// check what to do with the alpha channel (GX_PokeAlphaRead) // check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode();
if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) if (bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24)
{ {
color = RGBA8ToRGBA6ToRGBA8(color); color = RGBA8ToRGBA6ToRGBA8(color);
} }
else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) else if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16)
{ {
color = RGBA8ToRGB565ToRGBA8(color); color = RGBA8ToRGB565ToRGBA8(color);
} }
if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) if (bpmem.zcontrol.pixel_format != PixelFormat::RGBA6_Z24)
{ {
color |= 0xFF000000; color |= 0xFF000000;
} }
@ -231,7 +231,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
depth = 1.0f - depth; depth = 1.0f - depth;
u32 ret = 0; u32 ret = 0;
if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16)
{ {
// if Z is in 16 bit format you must return a 16 bit integer // if Z is in 16 bit format you must return a 16 bit integer
ret = std::clamp<u32>(static_cast<u32>(depth * 65536.0f), 0, 0xFFFF); ret = std::clamp<u32>(static_cast<u32>(depth * 65536.0f), 0, 0xFFFF);
@ -994,10 +994,10 @@ bool Renderer::RecompileImGuiPipeline()
pconfig.depth_state = RenderState::GetNoDepthTestingDepthState(); pconfig.depth_state = RenderState::GetNoDepthTestingDepthState();
pconfig.blending_state = RenderState::GetNoBlendingBlendState(); pconfig.blending_state = RenderState::GetNoBlendingBlendState();
pconfig.blending_state.blendenable = true; pconfig.blending_state.blendenable = true;
pconfig.blending_state.srcfactor = BlendMode::SRCALPHA; pconfig.blending_state.srcfactor = SrcBlendFactor::SrcAlpha;
pconfig.blending_state.dstfactor = BlendMode::INVSRCALPHA; pconfig.blending_state.dstfactor = DstBlendFactor::InvSrcAlpha;
pconfig.blending_state.srcfactoralpha = BlendMode::ZERO; pconfig.blending_state.srcfactoralpha = SrcBlendFactor::Zero;
pconfig.blending_state.dstfactoralpha = BlendMode::ONE; pconfig.blending_state.dstfactoralpha = DstBlendFactor::One;
pconfig.framebuffer_state.color_texture_format = m_backbuffer_format; pconfig.framebuffer_state.color_texture_format = m_backbuffer_format;
pconfig.framebuffer_state.depth_texture_format = AbstractTextureFormat::Undefined; pconfig.framebuffer_state.depth_texture_format = AbstractTextureFormat::Undefined;
pconfig.framebuffer_state.samples = 1; pconfig.framebuffer_state.samples = 1;
@ -1697,7 +1697,7 @@ bool Renderer::UseVertexDepthRange() const
return false; return false;
// We need a full depth range if a ztexture is used. // We need a full depth range if a ztexture is used.
if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest) if (bpmem.ztex2.op != ZTexOp::Disabled && !bpmem.zcontrol.early_ztest)
return true; return true;
// If an inverted depth range is unsupported, we also need to check if the range is inverted. // If an inverted depth range is unsupported, we also need to check if the range is inverted.

View file

@ -232,8 +232,8 @@ public:
// Called when the configuration changes, and backend structures need to be updated. // Called when the configuration changes, and backend structures need to be updated.
virtual void OnConfigChanged(u32 bits) {} virtual void OnConfigChanged(u32 bits) {}
PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; } void StorePixelFormat(PixelFormat new_format) { m_prev_efb_format = new_format; }
bool EFBHasAlphaChannel() const; bool EFBHasAlphaChannel() const;
VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); } VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); }
// Final surface changing // Final surface changing
@ -343,7 +343,7 @@ protected:
private: private:
std::tuple<int, int> CalculateOutputDimensions(int width, int height) const; std::tuple<int, int> CalculateOutputDimensions(int width, int height) const;
PEControl::PixelFormat m_prev_efb_format = PEControl::INVALID_FMT; PixelFormat m_prev_efb_format = PixelFormat::INVALID_FMT;
unsigned int m_efb_scale = 1; unsigned int m_efb_scale = 1;
// These will be set on the first call to SetWindowSize. // These will be set on the first call to SetWindowSize.

View file

@ -15,7 +15,7 @@ void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_ty
// Back-face culling should be disabled for points/lines. // Back-face culling should be disabled for points/lines.
if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip) if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip)
cullmode = GenMode::CULL_NONE; cullmode = CullMode::None;
} }
RasterizationState& RasterizationState::operator=(const RasterizationState& rhs) RasterizationState& RasterizationState::operator=(const RasterizationState& rhs)
@ -47,14 +47,27 @@ DepthState& DepthState::operator=(const DepthState& rhs)
// ONE on blending. As the backends may emulate this framebuffer // ONE on blending. As the backends may emulate this framebuffer
// configuration with an alpha channel, we just drop all references // configuration with an alpha channel, we just drop all references
// to the destination alpha channel. // to the destination alpha channel.
static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor) static SrcBlendFactor RemoveDstAlphaUsage(SrcBlendFactor factor)
{ {
switch (factor) switch (factor)
{ {
case BlendMode::DSTALPHA: case SrcBlendFactor::DstAlpha:
return BlendMode::ONE; return SrcBlendFactor::One;
case BlendMode::INVDSTALPHA: case SrcBlendFactor::InvDstAlpha:
return BlendMode::ZERO; return SrcBlendFactor::Zero;
default:
return factor;
}
}
static DstBlendFactor RemoveDstAlphaUsage(DstBlendFactor factor)
{
switch (factor)
{
case DstBlendFactor::DstAlpha:
return DstBlendFactor::One;
case DstBlendFactor::InvDstAlpha:
return DstBlendFactor::Zero;
default: default:
return factor; return factor;
} }
@ -64,14 +77,14 @@ static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor)
// the alpha component, CLR and ALPHA are indentical. So just always // the alpha component, CLR and ALPHA are indentical. So just always
// use ALPHA as this makes it easier for the backends to use the second // use ALPHA as this makes it easier for the backends to use the second
// alpha value of dual source blending. // alpha value of dual source blending.
static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor) static DstBlendFactor RemoveSrcColorUsage(DstBlendFactor factor)
{ {
switch (factor) switch (factor)
{ {
case BlendMode::SRCCLR: case DstBlendFactor::SrcClr:
return BlendMode::SRCALPHA; return DstBlendFactor::SrcAlpha;
case BlendMode::INVSRCCLR: case DstBlendFactor::InvSrcClr:
return BlendMode::INVSRCALPHA; return DstBlendFactor::InvSrcAlpha;
default: default:
return factor; return factor;
} }
@ -79,14 +92,14 @@ static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor)
// Same as RemoveSrcColorUsage, but because of the overlapping enum, // Same as RemoveSrcColorUsage, but because of the overlapping enum,
// this must be written as another function. // this must be written as another function.
static BlendMode::BlendFactor RemoveDstColorUsage(BlendMode::BlendFactor factor) static SrcBlendFactor RemoveDstColorUsage(SrcBlendFactor factor)
{ {
switch (factor) switch (factor)
{ {
case BlendMode::DSTCLR: case SrcBlendFactor::DstClr:
return BlendMode::DSTALPHA; return SrcBlendFactor::DstAlpha;
case BlendMode::INVDSTCLR: case SrcBlendFactor::InvDstClr:
return BlendMode::INVDSTALPHA; return SrcBlendFactor::InvDstAlpha;
default: default:
return factor; return factor;
} }
@ -97,11 +110,11 @@ void BlendingState::Generate(const BPMemory& bp)
// Start with everything disabled. // Start with everything disabled.
hex = 0; hex = 0;
bool target_has_alpha = bp.zcontrol.pixel_format == PEControl::RGBA6_Z24; bool target_has_alpha = bp.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
bool alpha_test_may_success = bp.alpha_test.TestResult() != AlphaTest::FAIL; bool alpha_test_may_succeed = bp.alpha_test.TestResult() != AlphaTestResult::Fail;
colorupdate = bp.blendmode.colorupdate && alpha_test_may_success; colorupdate = bp.blendmode.colorupdate && alpha_test_may_succeed;
alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_success; alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_succeed;
dstalpha = bp.dstalpha.enable && alphaupdate; dstalpha = bp.dstalpha.enable && alphaupdate;
usedualsrc = true; usedualsrc = true;
@ -110,14 +123,14 @@ void BlendingState::Generate(const BPMemory& bp)
{ {
blendenable = true; blendenable = true;
subtractAlpha = subtract = true; subtractAlpha = subtract = true;
srcfactoralpha = srcfactor = BlendMode::ONE; srcfactoralpha = srcfactor = SrcBlendFactor::One;
dstfactoralpha = dstfactor = BlendMode::ONE; dstfactoralpha = dstfactor = DstBlendFactor::One;
if (dstalpha) if (dstalpha)
{ {
subtractAlpha = false; subtractAlpha = false;
srcfactoralpha = BlendMode::ONE; srcfactoralpha = SrcBlendFactor::One;
dstfactoralpha = BlendMode::ZERO; dstfactoralpha = DstBlendFactor::Zero;
} }
} }
@ -133,22 +146,22 @@ void BlendingState::Generate(const BPMemory& bp)
srcfactor = RemoveDstAlphaUsage(srcfactor); srcfactor = RemoveDstAlphaUsage(srcfactor);
dstfactor = RemoveDstAlphaUsage(dstfactor); dstfactor = RemoveDstAlphaUsage(dstfactor);
} }
// replaces SRCCLR with SRCALPHA and DSTCLR with DSTALPHA, it is important to // replaces SrcClr with SrcAlpha and DstClr with DstAlpha, it is important to
// use the dst function for the src factor and vice versa // use the dst function for the src factor and vice versa
srcfactoralpha = RemoveDstColorUsage(srcfactor); srcfactoralpha = RemoveDstColorUsage(srcfactor);
dstfactoralpha = RemoveSrcColorUsage(dstfactor); dstfactoralpha = RemoveSrcColorUsage(dstfactor);
if (dstalpha) if (dstalpha)
{ {
srcfactoralpha = BlendMode::ONE; srcfactoralpha = SrcBlendFactor::One;
dstfactoralpha = BlendMode::ZERO; dstfactoralpha = DstBlendFactor::Zero;
} }
} }
// The logicop bit has the lowest priority // The logicop bit has the lowest priority
else if (bp.blendmode.logicopenable) else if (bp.blendmode.logicopenable)
{ {
if (bp.blendmode.logicmode == BlendMode::NOOP) if (bp.blendmode.logicmode == LogicOp::NoOp)
{ {
// Fast path for Kirby's Return to Dreamland, they use it with dstAlpha. // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
colorupdate = false; colorupdate = false;
@ -169,38 +182,39 @@ void BlendingState::Generate(const BPMemory& bp)
void BlendingState::ApproximateLogicOpWithBlending() void BlendingState::ApproximateLogicOpWithBlending()
{ {
// Any of these which use SRC as srcFactor or DST as dstFactor won't be correct.
// This is because the two are aliased to one another (see the enum).
struct LogicOpApproximation struct LogicOpApproximation
{ {
bool subtract; bool subtract;
BlendMode::BlendFactor srcfactor; SrcBlendFactor srcfactor;
BlendMode::BlendFactor dstfactor; DstBlendFactor dstfactor;
}; };
// TODO: This previously had a warning about SRC and DST being aliased and not to mix them,
// but INVSRCCLR and INVDSTCLR were also aliased and were mixed.
// Thus, NOR, EQUIV, INVERT, COPY_INVERTED, and OR_INVERTED duplicate(d) other values.
static constexpr std::array<LogicOpApproximation, 16> approximations = {{ static constexpr std::array<LogicOpApproximation, 16> approximations = {{
{false, BlendMode::ZERO, BlendMode::ZERO}, // CLEAR {false, SrcBlendFactor::Zero, DstBlendFactor::Zero}, // CLEAR
{false, BlendMode::DSTCLR, BlendMode::ZERO}, // AND {false, SrcBlendFactor::DstClr, DstBlendFactor::Zero}, // AND
{true, BlendMode::ONE, BlendMode::INVSRCCLR}, // AND_REVERSE {true, SrcBlendFactor::One, DstBlendFactor::InvSrcClr}, // AND_REVERSE
{false, BlendMode::ONE, BlendMode::ZERO}, // COPY {false, SrcBlendFactor::One, DstBlendFactor::Zero}, // COPY
{true, BlendMode::DSTCLR, BlendMode::ONE}, // AND_INVERTED {true, SrcBlendFactor::DstClr, DstBlendFactor::One}, // AND_INVERTED
{false, BlendMode::ZERO, BlendMode::ONE}, // NOOP {false, SrcBlendFactor::Zero, DstBlendFactor::One}, // NOOP
{false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // XOR {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // XOR
{false, BlendMode::INVDSTCLR, BlendMode::ONE}, // OR {false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR
{false, BlendMode::INVSRCCLR, BlendMode::INVDSTCLR}, // NOR {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NOR
{false, BlendMode::INVSRCCLR, BlendMode::ZERO}, // EQUIV {false, SrcBlendFactor::InvDstClr, DstBlendFactor::Zero}, // EQUIV
{false, BlendMode::INVDSTCLR, BlendMode::INVDSTCLR}, // INVERT {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // INVERT
{false, BlendMode::ONE, BlendMode::INVDSTALPHA}, // OR_REVERSE {false, SrcBlendFactor::One, DstBlendFactor::InvDstAlpha}, // OR_REVERSE
{false, BlendMode::INVSRCCLR, BlendMode::INVSRCCLR}, // COPY_INVERTED {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // COPY_INVERTED
{false, BlendMode::INVSRCCLR, BlendMode::ONE}, // OR_INVERTED {false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR_INVERTED
{false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // NAND {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NAND
{false, BlendMode::ONE, BlendMode::ONE}, // SET {false, SrcBlendFactor::One, DstBlendFactor::One}, // SET
}}; }};
logicopenable = false; logicopenable = false;
blendenable = true; blendenable = true;
subtract = approximations[logicmode].subtract; subtract = approximations[u32(logicmode.Value())].subtract;
srcfactor = approximations[logicmode].srcfactor; srcfactor = approximations[u32(logicmode.Value())].srcfactor;
dstfactor = approximations[logicmode].dstfactor; dstfactor = approximations[u32(logicmode.Value())].dstfactor;
} }
BlendingState& BlendingState::operator=(const BlendingState& rhs) BlendingState& BlendingState::operator=(const BlendingState& rhs)
@ -217,20 +231,20 @@ void SamplerState::Generate(const BPMemory& bp, u32 index)
// GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their // GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their
// sampler states. Therefore, we set the min/max LOD to zero if this option is used. // sampler states. Therefore, we set the min/max LOD to zero if this option is used.
min_filter = (tm0.min_filter & 4) != 0 ? Filter::Linear : Filter::Point; min_filter = tm0.min_filter == FilterMode::Linear ? Filter::Linear : Filter::Point;
mipmap_filter = (tm0.min_filter & 3) == TexMode0::TEXF_LINEAR ? Filter::Linear : Filter::Point; mipmap_filter = tm0.mipmap_filter == MipMode::Linear ? Filter::Linear : Filter::Point;
mag_filter = tm0.mag_filter != 0 ? Filter::Linear : Filter::Point; mag_filter = tm0.mag_filter == FilterMode::Linear ? Filter::Linear : Filter::Point;
// If mipmaps are disabled, clamp min/max lod // If mipmaps are disabled, clamp min/max lod
max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0; max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod.Value() : 0;
min_lod = std::min(max_lod.Value(), static_cast<u64>(tm1.min_lod)); min_lod = std::min(max_lod.Value(), static_cast<u64>(tm1.min_lod));
lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias * (256 / 32) : 0; lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias * (256 / 32) : 0;
// Address modes // Address modes
static constexpr std::array<AddressMode, 4> address_modes = { static constexpr std::array<AddressMode, 4> address_modes = {
{AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}}; {AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}};
wrap_u = address_modes[tm0.wrap_s]; wrap_u = address_modes[u32(tm0.wrap_s.Value())];
wrap_v = address_modes[tm0.wrap_t]; wrap_v = address_modes[u32(tm0.wrap_t.Value())];
anisotropic_filtering = 0; anisotropic_filtering = 0;
} }
@ -252,7 +266,7 @@ RasterizationState GetInvalidRasterizationState()
RasterizationState GetNoCullRasterizationState(PrimitiveType primitive) RasterizationState GetNoCullRasterizationState(PrimitiveType primitive)
{ {
RasterizationState state = {}; RasterizationState state = {};
state.cullmode = GenMode::CULL_NONE; state.cullmode = CullMode::None;
state.primitive = primitive; state.primitive = primitive;
return state; return state;
} }
@ -260,7 +274,7 @@ RasterizationState GetNoCullRasterizationState(PrimitiveType primitive)
RasterizationState GetCullBackFaceRasterizationState(PrimitiveType primitive) RasterizationState GetCullBackFaceRasterizationState(PrimitiveType primitive)
{ {
RasterizationState state = {}; RasterizationState state = {};
state.cullmode = GenMode::CULL_BACK; state.cullmode = CullMode::Back;
state.primitive = primitive; state.primitive = primitive;
return state; return state;
} }
@ -277,7 +291,7 @@ DepthState GetNoDepthTestingDepthState()
DepthState state = {}; DepthState state = {};
state.testenable = false; state.testenable = false;
state.updateenable = false; state.updateenable = false;
state.func = ZMode::ALWAYS; state.func = CompareMode::Always;
return state; return state;
} }
@ -286,7 +300,7 @@ DepthState GetAlwaysWriteDepthState()
DepthState state = {}; DepthState state = {};
state.testenable = true; state.testenable = true;
state.updateenable = true; state.updateenable = true;
state.func = ZMode::ALWAYS; state.func = CompareMode::Always;
return state; return state;
} }
@ -302,10 +316,10 @@ BlendingState GetNoBlendingBlendState()
BlendingState state = {}; BlendingState state = {};
state.usedualsrc = false; state.usedualsrc = false;
state.blendenable = false; state.blendenable = false;
state.srcfactor = BlendMode::ONE; state.srcfactor = SrcBlendFactor::One;
state.srcfactoralpha = BlendMode::ONE; state.srcfactoralpha = SrcBlendFactor::One;
state.dstfactor = BlendMode::ZERO; state.dstfactor = DstBlendFactor::Zero;
state.dstfactoralpha = BlendMode::ZERO; state.dstfactoralpha = DstBlendFactor::Zero;
state.logicopenable = false; state.logicopenable = false;
state.colorupdate = true; state.colorupdate = true;
state.alphaupdate = true; state.alphaupdate = true;
@ -317,10 +331,10 @@ BlendingState GetNoColorWriteBlendState()
BlendingState state = {}; BlendingState state = {};
state.usedualsrc = false; state.usedualsrc = false;
state.blendenable = false; state.blendenable = false;
state.srcfactor = BlendMode::ONE; state.srcfactor = SrcBlendFactor::One;
state.srcfactoralpha = BlendMode::ONE; state.srcfactoralpha = SrcBlendFactor::One;
state.dstfactor = BlendMode::ZERO; state.dstfactor = DstBlendFactor::Zero;
state.dstfactoralpha = BlendMode::ZERO; state.dstfactoralpha = DstBlendFactor::Zero;
state.logicopenable = false; state.logicopenable = false;
state.colorupdate = false; state.colorupdate = false;
state.alphaupdate = false; state.alphaupdate = false;

View file

@ -28,7 +28,7 @@ union RasterizationState
bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; } bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; }
bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; } bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; }
bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; } bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; }
BitField<0, 2, GenMode::CullMode> cullmode; BitField<0, 2, CullMode> cullmode;
BitField<3, 2, PrimitiveType> primitive; BitField<3, 2, PrimitiveType> primitive;
u32 hex; u32 hex;
@ -59,7 +59,7 @@ union DepthState
bool operator<(const DepthState& rhs) const { return hex < rhs.hex; } bool operator<(const DepthState& rhs) const { return hex < rhs.hex; }
BitField<0, 1, u32> testenable; BitField<0, 1, u32> testenable;
BitField<1, 1, u32> updateenable; BitField<1, 1, u32> updateenable;
BitField<2, 3, ZMode::CompareMode> func; BitField<2, 3, CompareMode> func;
u32 hex; u32 hex;
}; };
@ -85,11 +85,11 @@ union BlendingState
BitField<5, 1, u32> subtract; BitField<5, 1, u32> subtract;
BitField<6, 1, u32> subtractAlpha; BitField<6, 1, u32> subtractAlpha;
BitField<7, 1, u32> usedualsrc; BitField<7, 1, u32> usedualsrc;
BitField<8, 3, BlendMode::BlendFactor> dstfactor; BitField<8, 3, DstBlendFactor> dstfactor;
BitField<11, 3, BlendMode::BlendFactor> srcfactor; BitField<11, 3, SrcBlendFactor> srcfactor;
BitField<14, 3, BlendMode::BlendFactor> dstfactoralpha; BitField<14, 3, DstBlendFactor> dstfactoralpha;
BitField<17, 3, BlendMode::BlendFactor> srcfactoralpha; BitField<17, 3, SrcBlendFactor> srcfactoralpha;
BitField<20, 4, BlendMode::LogicOp> logicmode; BitField<20, 4, LogicOp> logicmode;
u32 hex; u32 hex;
}; };

View file

@ -16,13 +16,13 @@ namespace SamplerCommon
template <class T> template <class T>
constexpr bool IsBpTexMode0PointFiltering(const T& tm0) constexpr bool IsBpTexMode0PointFiltering(const T& tm0)
{ {
return tm0.min_filter < 4 && !tm0.mag_filter; return tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near;
} }
// Check if the minification filter has mipmap based filtering modes enabled. // Check if the minification filter has mipmap based filtering modes enabled.
template <class T> template <class T>
constexpr bool AreBpTexMode0MipmapsEnabled(const T& tm0) constexpr bool AreBpTexMode0MipmapsEnabled(const T& tm0)
{ {
return (tm0.min_filter & 3) != 0; return tm0.mipmap_filter != MipMode::None;
} }
} // namespace SamplerCommon } // namespace SamplerCommon

View file

@ -1115,7 +1115,7 @@ void ShaderCache::QueueUberShaderPipelines()
{ {
// uint_output is only ever enabled when logic ops are enabled. // uint_output is only ever enabled when logic ops are enabled.
config.blending_state.logicopenable = true; config.blending_state.logicopenable = true;
config.blending_state.logicmode = BlendMode::AND; config.blending_state.logicmode = LogicOp::And;
} }
auto iter = m_gx_uber_pipeline_cache.find(config); auto iter = m_gx_uber_pipeline_cache.find(config);

View file

@ -1187,12 +1187,12 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage)
const u32 address = (tex.texImage3[id].image_base /* & 0x1FFFFF*/) << 5; const u32 address = (tex.texImage3[id].image_base /* & 0x1FFFFF*/) << 5;
u32 width = tex.texImage0[id].width + 1; u32 width = tex.texImage0[id].width + 1;
u32 height = tex.texImage0[id].height + 1; u32 height = tex.texImage0[id].height + 1;
const TextureFormat texformat = static_cast<TextureFormat>(tex.texImage0[id].format); const TextureFormat texformat = tex.texImage0[id].format;
const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9; const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9;
const TLUTFormat tlutfmt = static_cast<TLUTFormat>(tex.texTlut[id].tlut_format); const TLUTFormat tlutfmt = tex.texTlut[id].tlut_format;
const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]); const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]);
u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1; u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1;
const bool from_tmem = tex.texImage1[id].image_type != 0; const bool from_tmem = tex.texImage1[id].cache_manually_managed != 0;
const u32 tmem_address_even = from_tmem ? tex.texImage1[id].tmem_even * TMEM_LINE_SIZE : 0; const u32 tmem_address_even = from_tmem ? tex.texImage1[id].tmem_even * TMEM_LINE_SIZE : 0;
const u32 tmem_address_odd = from_tmem ? tex.texImage2[id].tmem_odd * TMEM_LINE_SIZE : 0; const u32 tmem_address_odd = from_tmem ? tex.texImage2[id].tmem_odd * TMEM_LINE_SIZE : 0;
@ -2204,7 +2204,7 @@ void TextureCacheBase::CopyRenderTargetToTexture(
if (copy_to_ram) if (copy_to_ram)
{ {
EFBCopyFilterCoefficients coefficients = GetRAMCopyFilterCoefficients(filter_coefficients); EFBCopyFilterCoefficients coefficients = GetRAMCopyFilterCoefficients(filter_coefficients);
PEControl::PixelFormat srcFormat = bpmem.zcontrol.pixel_format; PixelFormat srcFormat = bpmem.zcontrol.pixel_format;
EFBCopyParams format(srcFormat, dstFormat, is_depth_copy, isIntensity, EFBCopyParams format(srcFormat, dstFormat, is_depth_copy, isIntensity,
NeedsCopyFilterInShader(coefficients)); NeedsCopyFilterInShader(coefficients));

View file

@ -50,8 +50,8 @@ struct TextureAndTLUTFormat
struct EFBCopyParams struct EFBCopyParams
{ {
EFBCopyParams(PEControl::PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, EFBCopyParams(PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, bool yuv_,
bool yuv_, bool copy_filter_) bool copy_filter_)
: efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_), : efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_),
copy_filter(copy_filter_) copy_filter(copy_filter_)
{ {
@ -63,7 +63,7 @@ struct EFBCopyParams
std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv, rhs.copy_filter); std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv, rhs.copy_filter);
} }
PEControl::PixelFormat efb_format; PixelFormat efb_format;
EFBCopyFormat copy_format; EFBCopyFormat copy_format;
bool depth; bool depth;
bool yuv; bool yuv;

View file

@ -127,13 +127,13 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A
{ {
switch (params.efb_format) switch (params.efb_format)
{ {
case PEControl::RGB8_Z24: case PixelFormat::RGB8_Z24:
code.Write("RGBA8ToRGB8("); code.Write("RGBA8ToRGB8(");
break; break;
case PEControl::RGBA6_Z24: case PixelFormat::RGBA6_Z24:
code.Write("RGBA8ToRGBA6("); code.Write("RGBA8ToRGBA6(");
break; break;
case PEControl::RGB565_Z16: case PixelFormat::RGB565_Z16:
code.Write("RGBA8ToRGB565("); code.Write("RGBA8ToRGB565(");
break; break;
default: default:

View file

@ -19,7 +19,7 @@ TCShaderUid GetShaderUid(EFBCopyFormat dst_format, bool is_depth_copy, bool is_i
UidData* const uid_data = out.GetUidData(); UidData* const uid_data = out.GetUidData();
uid_data->dst_format = dst_format; uid_data->dst_format = dst_format;
uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
uid_data->is_depth_copy = is_depth_copy; uid_data->is_depth_copy = is_depth_copy;
uid_data->is_intensity = is_intensity; uid_data->is_intensity = is_intensity;
uid_data->scale_by_half = scale_by_half; uid_data->scale_by_half = scale_by_half;

View file

@ -6,6 +6,7 @@
#include <tuple> #include <tuple>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
enum enum
{ {
@ -32,8 +33,17 @@ enum class TextureFormat
// Special texture format used to represent YUVY xfb copies. // Special texture format used to represent YUVY xfb copies.
// They aren't really textures, but they share so much hardware and usecases that it makes sense // They aren't really textures, but they share so much hardware and usecases that it makes sense
// to emulate them as part of texture cache. // to emulate them as part of texture cache.
// This isn't a real value that can be used on console; it only exists for ease of implementation.
XFB = 0xF, XFB = 0xF,
}; };
template <>
struct fmt::formatter<TextureFormat> : EnumFormatter<TextureFormat::CMPR>
{
static constexpr array_type names = {"I4", "I8", "IA4", "IA8", "RGB565",
"RGB5A3", "RGBA8", nullptr, "C4", "C8",
"C14X2", nullptr, nullptr, nullptr, "CMPR"};
formatter() : EnumFormatter(names) {}
};
static inline bool IsColorIndexed(TextureFormat format) static inline bool IsColorIndexed(TextureFormat format)
{ {
@ -82,8 +92,20 @@ enum class EFBCopyFormat
// Special texture format used to represent YUVY xfb copies. // Special texture format used to represent YUVY xfb copies.
// They aren't really textures, but they share so much hardware and usecases that it makes sense // They aren't really textures, but they share so much hardware and usecases that it makes sense
// to emulate them as part of texture cache. // to emulate them as part of texture cache.
// This isn't a real value that can be used on console; it only exists for ease of implementation.
XFB = 0xF, XFB = 0xF,
}; };
template <>
struct fmt::formatter<EFBCopyFormat> : EnumFormatter<EFBCopyFormat::GB8>
{
static constexpr array_type names = {
"R4/I4/Z4", "R8/I8/Z8H (?)", "RA4/IA4", "RA8/IA8 (Z16 too?)",
"RGB565", "RGB5A3", "RGBA8", "A8",
"R8/I8/Z8H", "G8/Z8M", "B8/Z8L", "RG8/Z16R (Note: G and R are reversed)",
"GB8/Z16L",
};
formatter() : EnumFormatter(names) {}
};
enum class TLUTFormat enum class TLUTFormat
{ {
@ -92,6 +114,11 @@ enum class TLUTFormat
RGB565 = 0x1, RGB565 = 0x1,
RGB5A3 = 0x2, RGB5A3 = 0x2,
}; };
template <>
struct fmt::formatter<TLUTFormat> : EnumFormatter<TLUTFormat::RGB5A3>
{
formatter() : EnumFormatter({"IA8", "RGB565", "RGB5A3"}) {}
};
static inline bool IsValidTLUTFormat(TLUTFormat tlutfmt) static inline bool IsValidTLUTFormat(TLUTFormat tlutfmt)
{ {

View file

@ -22,12 +22,12 @@ PixelShaderUid GetPixelShaderUid()
pixel_ubershader_uid_data* const uid_data = out.GetUidData(); pixel_ubershader_uid_data* const uid_data = out.GetUidData();
uid_data->num_texgens = xfmem.numTexGen.numTexGens; uid_data->num_texgens = xfmem.numTexGen.numTexGens;
uid_data->early_depth = uid_data->early_depth = bpmem.UseEarlyDepthTest() &&
bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc ||
(g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) && bpmem.alpha_test.TestResult() == AlphaTestResult::Undetermined) &&
!(bpmem.zmode.testenable && bpmem.genMode.zfreeze); !(bpmem.zmode.testenable && bpmem.genMode.zfreeze);
uid_data->per_pixel_depth = uid_data->per_pixel_depth =
(bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (bpmem.ztex2.op != ZTexOp::Disabled && bpmem.UseLateDepthTest()) ||
(!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !uid_data->early_depth) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !uid_data->early_depth) ||
(bpmem.zmode.testenable && bpmem.genMode.zfreeze); (bpmem.zmode.testenable && bpmem.genMode.zfreeze);
uid_data->uint_output = bpmem.blendmode.UseLogicOp(); uid_data->uint_output = bpmem.blendmode.UseLogicOp();
@ -367,21 +367,21 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
"// which are common to both color and alpha channels\n" "// which are common to both color and alpha channels\n"
"bool tevCompare(uint op, int3 color_A, int3 color_B) {{\n" "bool tevCompare(uint op, int3 color_A, int3 color_B) {{\n"
" switch (op) {{\n" " switch (op) {{\n"
" case 0u: // TEVCMP_R8_GT\n" " case 0u: // TevCompareMode::R8, TevComparison::GT\n"
" return (color_A.r > color_B.r);\n" " return (color_A.r > color_B.r);\n"
" case 1u: // TEVCMP_R8_EQ\n" " case 1u: // TevCompareMode::R8, TevComparison::EQ\n"
" return (color_A.r == color_B.r);\n" " return (color_A.r == color_B.r);\n"
" case 2u: // TEVCMP_GR16_GT\n" " case 2u: // TevCompareMode::GR16, TevComparison::GT\n"
" int A_16 = (color_A.r | (color_A.g << 8));\n" " int A_16 = (color_A.r | (color_A.g << 8));\n"
" int B_16 = (color_B.r | (color_B.g << 8));\n" " int B_16 = (color_B.r | (color_B.g << 8));\n"
" return A_16 > B_16;\n" " return A_16 > B_16;\n"
" case 3u: // TEVCMP_GR16_EQ\n" " case 3u: // TevCompareMode::GR16, TevComparison::EQ\n"
" return (color_A.r == color_B.r && color_A.g == color_B.g);\n" " return (color_A.r == color_B.r && color_A.g == color_B.g);\n"
" case 4u: // TEVCMP_BGR24_GT\n" " case 4u: // TevCompareMode::BGR24, TevComparison::GT\n"
" int A_24 = (color_A.r | (color_A.g << 8) | (color_A.b << 16));\n" " int A_24 = (color_A.r | (color_A.g << 8) | (color_A.b << 16));\n"
" int B_24 = (color_B.r | (color_B.g << 8) | (color_B.b << 16));\n" " int B_24 = (color_B.r | (color_B.g << 8) | (color_B.b << 16));\n"
" return A_24 > B_24;\n" " return A_24 > B_24;\n"
" case 5u: // TEVCMP_BGR24_EQ\n" " case 5u: // TevCompareMode::BGR24, TevComparison::EQ\n"
" return (color_A.r == color_B.r && color_A.g == color_B.g && color_A.b == color_B.b);\n" " return (color_A.r == color_B.r && color_A.g == color_B.g && color_A.b == color_B.b);\n"
" default:\n" " default:\n"
" return false;\n" " return false;\n"
@ -814,29 +814,29 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" s.AlphaBump = indcoord[bs - 1u];\n" " s.AlphaBump = indcoord[bs - 1u];\n"
" switch(fmt)\n" " switch(fmt)\n"
" {{\n" " {{\n"
" case {}u:\n", " case {:s}:\n",
ITF_8); IndTexFormat::ITF_8);
out.Write(" indcoord.x = indcoord.x + ((bias & 1u) != 0u ? -128 : 0);\n" out.Write(" indcoord.x = indcoord.x + ((bias & 1u) != 0u ? -128 : 0);\n"
" indcoord.y = indcoord.y + ((bias & 2u) != 0u ? -128 : 0);\n" " indcoord.y = indcoord.y + ((bias & 2u) != 0u ? -128 : 0);\n"
" indcoord.z = indcoord.z + ((bias & 4u) != 0u ? -128 : 0);\n" " indcoord.z = indcoord.z + ((bias & 4u) != 0u ? -128 : 0);\n"
" s.AlphaBump = s.AlphaBump & 0xf8;\n" " s.AlphaBump = s.AlphaBump & 0xf8;\n"
" break;\n" " break;\n"
" case {}u:\n", " case {:s}:\n",
ITF_5); IndTexFormat::ITF_5);
out.Write(" indcoord.x = (indcoord.x & 0x1f) + ((bias & 1u) != 0u ? 1 : 0);\n" out.Write(" indcoord.x = (indcoord.x & 0x1f) + ((bias & 1u) != 0u ? 1 : 0);\n"
" indcoord.y = (indcoord.y & 0x1f) + ((bias & 2u) != 0u ? 1 : 0);\n" " indcoord.y = (indcoord.y & 0x1f) + ((bias & 2u) != 0u ? 1 : 0);\n"
" indcoord.z = (indcoord.z & 0x1f) + ((bias & 4u) != 0u ? 1 : 0);\n" " indcoord.z = (indcoord.z & 0x1f) + ((bias & 4u) != 0u ? 1 : 0);\n"
" s.AlphaBump = s.AlphaBump & 0xe0;\n" " s.AlphaBump = s.AlphaBump & 0xe0;\n"
" break;\n" " break;\n"
" case {}u:\n", " case {:s}:\n",
ITF_4); IndTexFormat::ITF_4);
out.Write(" indcoord.x = (indcoord.x & 0x0f) + ((bias & 1u) != 0u ? 1 : 0);\n" out.Write(" indcoord.x = (indcoord.x & 0x0f) + ((bias & 1u) != 0u ? 1 : 0);\n"
" indcoord.y = (indcoord.y & 0x0f) + ((bias & 2u) != 0u ? 1 : 0);\n" " indcoord.y = (indcoord.y & 0x0f) + ((bias & 2u) != 0u ? 1 : 0);\n"
" indcoord.z = (indcoord.z & 0x0f) + ((bias & 4u) != 0u ? 1 : 0);\n" " indcoord.z = (indcoord.z & 0x0f) + ((bias & 4u) != 0u ? 1 : 0);\n"
" s.AlphaBump = s.AlphaBump & 0xf0;\n" " s.AlphaBump = s.AlphaBump & 0xf0;\n"
" break;\n" " break;\n"
" case {}u:\n", " case {:s}:\n",
ITF_3); IndTexFormat::ITF_3);
out.Write(" indcoord.x = (indcoord.x & 0x07) + ((bias & 1u) != 0u ? 1 : 0);\n" out.Write(" indcoord.x = (indcoord.x & 0x07) + ((bias & 1u) != 0u ? 1 : 0);\n"
" indcoord.y = (indcoord.y & 0x07) + ((bias & 2u) != 0u ? 1 : 0);\n" " indcoord.y = (indcoord.y & 0x07) + ((bias & 2u) != 0u ? 1 : 0);\n"
" indcoord.z = (indcoord.z & 0x07) + ((bias & 4u) != 0u ? 1 : 0);\n" " indcoord.z = (indcoord.z & 0x07) + ((bias & 4u) != 0u ? 1 : 0);\n"
@ -924,7 +924,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" bool color_clamp = bool({});\n", out.Write(" bool color_clamp = bool({});\n",
BitfieldExtract("ss.cc", TevStageCombiner().colorC.clamp)); BitfieldExtract("ss.cc", TevStageCombiner().colorC.clamp));
out.Write(" uint color_shift = {};\n", out.Write(" uint color_shift = {};\n",
BitfieldExtract("ss.cc", TevStageCombiner().colorC.shift)); BitfieldExtract("ss.cc", TevStageCombiner().colorC.scale));
out.Write(" uint color_dest = {};\n", out.Write(" uint color_dest = {};\n",
BitfieldExtract("ss.cc", TevStageCombiner().colorC.dest)); BitfieldExtract("ss.cc", TevStageCombiner().colorC.dest));
@ -949,12 +949,12 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" }} else {{ // Compare mode\n" " }} else {{ // Compare mode\n"
" // op 6 and 7 do a select per color channel\n" " // op 6 and 7 do a select per color channel\n"
" if (color_compare_op == 6u) {{\n" " if (color_compare_op == 6u) {{\n"
" // TEVCMP_RGB8_GT\n" " // TevCompareMode::RGB8, TevComparison::GT\n"
" color.r = (color_A.r > color_B.r) ? color_C.r : 0;\n" " color.r = (color_A.r > color_B.r) ? color_C.r : 0;\n"
" color.g = (color_A.g > color_B.g) ? color_C.g : 0;\n" " color.g = (color_A.g > color_B.g) ? color_C.g : 0;\n"
" color.b = (color_A.b > color_B.b) ? color_C.b : 0;\n" " color.b = (color_A.b > color_B.b) ? color_C.b : 0;\n"
" }} else if (color_compare_op == 7u) {{\n" " }} else if (color_compare_op == 7u) {{\n"
" // TEVCMP_RGB8_EQ\n" " // TevCompareMode::RGB8, TevComparison::EQ\n"
" color.r = (color_A.r == color_B.r) ? color_C.r : 0;\n" " color.r = (color_A.r == color_B.r) ? color_C.r : 0;\n"
" color.g = (color_A.g == color_B.g) ? color_C.g : 0;\n" " color.g = (color_A.g == color_B.g) ? color_C.g : 0;\n"
" color.b = (color_A.b == color_B.b) ? color_C.b : 0;\n" " color.b = (color_A.b == color_B.b) ? color_C.b : 0;\n"
@ -990,7 +990,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" bool alpha_clamp = bool({});\n", out.Write(" bool alpha_clamp = bool({});\n",
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.clamp)); BitfieldExtract("ss.ac", TevStageCombiner().alphaC.clamp));
out.Write(" uint alpha_shift = {};\n", out.Write(" uint alpha_shift = {};\n",
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.shift)); BitfieldExtract("ss.ac", TevStageCombiner().alphaC.scale));
out.Write(" uint alpha_dest = {};\n", out.Write(" uint alpha_dest = {};\n",
BitfieldExtract("ss.ac", TevStageCombiner().alphaC.dest)); BitfieldExtract("ss.ac", TevStageCombiner().alphaC.dest));
@ -1016,10 +1016,10 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
"true, alpha_shift);\n" "true, alpha_shift);\n"
" }} else {{ // Compare mode\n" " }} else {{ // Compare mode\n"
" if (alpha_compare_op == 6u) {{\n" " if (alpha_compare_op == 6u) {{\n"
" // TEVCMP_A8_GT\n" " // TevCompareMode::A8, TevComparison::GT\n"
" alpha = (alpha_A > alpha_B) ? alpha_C : 0;\n" " alpha = (alpha_A > alpha_B) ? alpha_C : 0;\n"
" }} else if (alpha_compare_op == 7u) {{\n" " }} else if (alpha_compare_op == 7u) {{\n"
" // TEVCMP_A8_EQ\n" " // TevCompareMode::A8, TevComparison::EQ\n"
" alpha = (alpha_A == alpha_B) ? alpha_C : 0;\n" " alpha = (alpha_A == alpha_B) ? alpha_C : 0;\n"
" }} else {{\n" " }} else {{\n"
" // All remaining alpha compare ops actually compare the color channels\n" " // All remaining alpha compare ops actually compare the color channels\n"
@ -1157,8 +1157,8 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
out.Write(" // Fog\n" out.Write(" // Fog\n"
" uint fog_function = {};\n", " uint fog_function = {};\n",
BitfieldExtract("bpmem_fogParam3", FogParam3().fsel)); BitfieldExtract("bpmem_fogParam3", FogParam3().fsel));
out.Write(" if (fog_function != 0u) {{\n" out.Write(" if (fog_function != {:s}) {{\n", FogType::Off);
" // TODO: This all needs to be converted from float to fixed point\n" out.Write(" // TODO: This all needs to be converted from float to fixed point\n"
" float ze;\n" " float ze;\n"
" if ({} == 0u) {{\n", " if ({} == 0u) {{\n",
BitfieldExtract("bpmem_fogParam3", FogParam3().proj)); BitfieldExtract("bpmem_fogParam3", FogParam3().proj));
@ -1188,23 +1188,27 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
" }}\n" " }}\n"
"\n" "\n"
" float fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n" " float fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n"
"\n" "\n");
" if (fog_function > 3u) {{\n" out.Write(" if (fog_function >= {:s}) {{\n", FogType::Exp);
" switch (fog_function) {{\n" out.Write(" switch (fog_function) {{\n"
" case 4u:\n" " case {:s}:\n"
" fog = 1.0 - exp2(-8.0 * fog);\n" " fog = 1.0 - exp2(-8.0 * fog);\n"
" break;\n" " break;\n",
" case 5u:\n" FogType::Exp);
out.Write(" case {:s}:\n"
" fog = 1.0 - exp2(-8.0 * fog * fog);\n" " fog = 1.0 - exp2(-8.0 * fog * fog);\n"
" break;\n" " break;\n",
" case 6u:\n" FogType::ExpSq);
out.Write(" case {:s}:\n"
" fog = exp2(-8.0 * (1.0 - fog));\n" " fog = exp2(-8.0 * (1.0 - fog));\n"
" break;\n" " break;\n",
" case 7u:\n" FogType::BackwardsExp);
out.Write(" case {:s}:\n"
" fog = 1.0 - fog;\n" " fog = 1.0 - fog;\n"
" fog = exp2(-8.0 * fog * fog);\n" " fog = exp2(-8.0 * fog * fog);\n"
" break;\n" " break;\n",
" }}\n" FogType::BackwardsExpSq);
out.Write(" }}\n"
" }}\n" " }}\n"
"\n" "\n"
" int ifog = iround(fog * 256.0);\n" " int ifog = iround(fog * 256.0);\n"

View file

@ -293,7 +293,7 @@ int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bo
// if cull mode is CULL_ALL, tell VertexManager to skip triangles and quads. // if cull mode is CULL_ALL, tell VertexManager to skip triangles and quads.
// They still need to go through vertex loading, because we need to calculate a zfreeze refrence // They still need to go through vertex loading, because we need to calculate a zfreeze refrence
// slope. // slope.
bool cullall = (bpmem.genMode.cullmode == GenMode::CULL_ALL && primitive < 5); bool cullall = (bpmem.genMode.cullmode == CullMode::All && primitive < 5);
DataReader dst = g_vertex_manager->PrepareForAdditionalData( DataReader dst = g_vertex_manager->PrepareForAdditionalData(
primitive, count, loader->m_native_vtx_decl.stride, cullall); primitive, count, loader->m_native_vtx_decl.stride, cullall);