Merge pull request #10412 from Pokechu22/sw-efb-peek-alpha

Software: Implement pixel engine alpha read mode
This commit is contained in:
JMC47 2022-04-07 17:01:56 -04:00 committed by GitHub
commit e02194057b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 156 additions and 87 deletions

View File

@ -20,6 +20,7 @@
#include "VideoCommon/AbstractShader.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoCommon.h"
@ -132,6 +133,27 @@ u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
// check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine::AlphaReadMode alpha_read_mode = PixelEngine::GetAlphaReadMode();
if (alpha_read_mode == PixelEngine::AlphaReadMode::ReadNone)
{
// value is OK as it is
}
else if (alpha_read_mode == PixelEngine::AlphaReadMode::ReadFF)
{
value |= 0xFF000000;
}
else
{
if (alpha_read_mode != PixelEngine::AlphaReadMode::Read00)
{
PanicAlertFmt("Invalid PE alpha read mode: {}", static_cast<u16>(alpha_read_mode));
}
value &= 0x00FFFFFF;
}
break;
}
default:

View File

@ -1,12 +1,11 @@
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// http://www.nvidia.com/object/General_FAQ.html#t6 !!!!!
#include "VideoCommon/PixelEngine.h"
#include <mutex>
#include "Common/BitField.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
@ -26,70 +25,115 @@
namespace PixelEngine
{
// Note: These enums are (assumed to be) identical to the one in BPMemory, but the base type is set
// to u16 instead of u32 for BitField
enum class CompareMode : u16
{
Never = 0,
Less = 1,
Equal = 2,
LEqual = 3,
Greater = 4,
NEqual = 5,
GEqual = 6,
Always = 7
};
union UPEZConfReg
{
u16 Hex;
struct
{
u16 ZCompEnable : 1; // Z Comparator Enable
u16 Function : 3;
u16 ZUpdEnable : 1;
u16 : 11;
};
u16 hex;
BitField<0, 1, bool, u16> z_comparator_enable;
BitField<1, 3, CompareMode, u16> function;
BitField<4, 1, bool, u16> z_update_enable;
};
enum class SrcBlendFactor : u16
{
Zero = 0,
One = 1,
DstClr = 2,
InvDstClr = 3,
SrcAlpha = 4,
InvSrcAlpha = 5,
DstAlpha = 6,
InvDstAlpha = 7
};
enum class DstBlendFactor : u16
{
Zero = 0,
One = 1,
SrcClr = 2,
InvSrcClr = 3,
SrcAlpha = 4,
InvSrcAlpha = 5,
DstAlpha = 6,
InvDstAlpha = 7
};
enum class LogicOp : u16
{
Clear = 0,
And = 1,
AndReverse = 2,
Copy = 3,
AndInverted = 4,
NoOp = 5,
Xor = 6,
Or = 7,
Nor = 8,
Equiv = 9,
Invert = 10,
OrReverse = 11,
CopyInverted = 12,
OrInverted = 13,
Nand = 14,
Set = 15
};
union UPEAlphaConfReg
{
u16 Hex;
struct
{
u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT
u16 BMLogic : 1; // GX_BM_LOGIC
u16 Dither : 1;
u16 ColorUpdEnable : 1;
u16 AlphaUpdEnable : 1;
u16 DstFactor : 3;
u16 SrcFactor : 3;
u16 Substract : 1; // Additive mode by default
u16 BlendOperator : 4;
};
u16 hex;
BitField<0, 1, bool, u16> blend; // Set for GX_BM_BLEND or GX_BM_SUBTRACT
BitField<1, 1, bool, u16> logic; // Set for GX_BM_LOGIC
BitField<2, 1, bool, u16> dither;
BitField<3, 1, bool, u16> color_update_enable;
BitField<4, 1, bool, u16> alpha_update_enable;
BitField<5, 3, DstBlendFactor, u16> dst_factor;
BitField<8, 3, SrcBlendFactor, u16> src_factor;
BitField<11, 1, bool, u16> subtract; // Set for GX_BM_SUBTRACT
BitField<12, 4, LogicOp, u16> logic_op;
};
union UPEDstAlphaConfReg
{
u16 Hex;
struct
{
u16 DstAlpha : 8;
u16 Enable : 1;
u16 : 7;
};
u16 hex;
BitField<0, 8, u8, u16> alpha;
BitField<8, 1, bool, u16> enable;
};
union UPEAlphaModeConfReg
{
u16 Hex;
struct
{
u16 Threshold : 8;
u16 CompareMode : 8;
};
u16 hex;
BitField<0, 8, u8, u16> threshold;
// Yagcd and libogc use 8 bits for this, but the enum only needs 3
BitField<8, 3, CompareMode, u16> compare_mode;
};
union UPEAlphaReadReg
{
u16 hex;
BitField<0, 2, AlphaReadMode, u16> read_mode;
};
// fifo Control Register
union UPECtrlReg
{
struct
{
u16 PETokenEnable : 1;
u16 PEFinishEnable : 1;
u16 PEToken : 1; // write only
u16 PEFinish : 1; // write only
u16 : 12;
};
u16 Hex;
UPECtrlReg() { Hex = 0; }
UPECtrlReg(u16 _hex) { Hex = _hex; }
u16 hex;
BitField<0, 1, bool, u16> pe_token_enable;
BitField<1, 1, bool, u16> pe_finish_enable;
BitField<2, 1, bool, u16> pe_token; // Write only
BitField<3, 1, bool, u16> pe_finish; // Write only
};
// STATE_TO_SAVE
@ -142,12 +186,12 @@ static void SetTokenFinish_OnMainThread(u64 userdata, s64 cyclesLate);
void Init()
{
m_Control.Hex = 0;
m_ZConf.Hex = 0;
m_AlphaConf.Hex = 0;
m_DstAlphaConf.Hex = 0;
m_AlphaModeConf.Hex = 0;
m_AlphaRead.Hex = 0;
m_Control.hex = 0;
m_ZConf.hex = 0;
m_AlphaConf.hex = 0;
m_DstAlphaConf.hex = 0;
m_AlphaModeConf.hex = 0;
m_AlphaRead.hex = 0;
s_token = 0;
s_token_pending = 0;
@ -170,11 +214,11 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
u32 addr;
u16* ptr;
} directly_mapped_vars[] = {
{PE_ZCONF, &m_ZConf.Hex},
{PE_ALPHACONF, &m_AlphaConf.Hex},
{PE_DSTALPHACONF, &m_DstAlphaConf.Hex},
{PE_ALPHAMODE, &m_AlphaModeConf.Hex},
{PE_ALPHAREAD, &m_AlphaRead.Hex},
{PE_ZCONF, &m_ZConf.hex},
{PE_ALPHACONF, &m_AlphaConf.hex},
{PE_DSTALPHACONF, &m_DstAlphaConf.hex},
{PE_ALPHAMODE, &m_AlphaModeConf.hex},
{PE_ALPHAREAD, &m_AlphaRead.hex},
};
for (auto& mapped_var : directly_mapped_vars)
{
@ -209,20 +253,20 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
}
// Control register
mmio->Register(base | PE_CTRL_REGISTER, MMIO::DirectRead<u16>(&m_Control.Hex),
mmio->Register(base | PE_CTRL_REGISTER, MMIO::DirectRead<u16>(&m_Control.hex),
MMIO::ComplexWrite<u16>([](u32, u16 val) {
UPECtrlReg tmpCtrl(val);
UPECtrlReg tmpCtrl{.hex = val};
if (tmpCtrl.PEToken)
if (tmpCtrl.pe_token)
s_signal_token_interrupt = false;
if (tmpCtrl.PEFinish)
if (tmpCtrl.pe_finish)
s_signal_finish_interrupt = false;
m_Control.PETokenEnable = tmpCtrl.PETokenEnable;
m_Control.PEFinishEnable = tmpCtrl.PEFinishEnable;
m_Control.PEToken = 0; // this flag is write only
m_Control.PEFinish = 0; // this flag is write only
m_Control.pe_token_enable = tmpCtrl.pe_token_enable.Value();
m_Control.pe_finish_enable = tmpCtrl.pe_finish_enable.Value();
m_Control.pe_token = false; // this flag is write only
m_Control.pe_finish = false; // this flag is write only
DEBUG_LOG_FMT(PIXELENGINE, "(w16) CTRL_REGISTER: {:#06x}", val);
UpdateInterrupts();
@ -246,11 +290,11 @@ static void UpdateInterrupts()
{
// check if there is a token-interrupt
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN,
s_signal_token_interrupt && m_Control.PETokenEnable);
s_signal_token_interrupt && m_Control.pe_token_enable);
// check if there is a finish-interrupt
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH,
s_signal_finish_interrupt && m_Control.PEFinishEnable);
s_signal_finish_interrupt && m_Control.pe_finish_enable);
}
static void SetTokenFinish_OnMainThread(u64 userdata, s64 cyclesLate)
@ -327,9 +371,9 @@ void SetFinish(int cycles_into_future)
RaiseEvent(cycles_into_future);
}
UPEAlphaReadReg GetAlphaReadMode()
AlphaReadMode GetAlphaReadMode()
{
return m_AlphaRead;
return m_AlphaRead.read_mode;
}
} // namespace PixelEngine

View File

@ -4,7 +4,9 @@
#pragma once
#include "Common/CommonTypes.h"
class PointerWrap;
namespace MMIO
{
class Mapping;
@ -45,14 +47,11 @@ enum
};
// ReadMode specifies the returned alpha channel for EFB peeks
union UPEAlphaReadReg
enum class AlphaReadMode : u16
{
u16 Hex;
struct
{
u16 ReadMode : 2;
u16 : 14;
};
Read00 = 0, // Always read 0x00
ReadFF = 1, // Always read 0xFF
ReadNone = 2, // Always read the real alpha value
};
void Init();
@ -63,6 +62,6 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
// gfx backend support
void SetToken(const u16 token, const bool interrupt, int cycle_delay);
void SetFinish(int cycle_delay);
UPEAlphaReadReg GetAlphaReadMode();
AlphaReadMode GetAlphaReadMode();
} // namespace PixelEngine

View File

@ -247,9 +247,6 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
// a little-endian value is expected to be returned
color = ((color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000));
// check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode();
if (bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24)
{
color = RGBA8ToRGBA6ToRGBA8(color);
@ -263,17 +260,24 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
color |= 0xFF000000;
}
if (alpha_read_mode.ReadMode == 2)
// check what to do with the alpha channel (GX_PokeAlphaRead)
PixelEngine::AlphaReadMode alpha_read_mode = PixelEngine::GetAlphaReadMode();
if (alpha_read_mode == PixelEngine::AlphaReadMode::ReadNone)
{
return color; // GX_READ_NONE
return color;
}
else if (alpha_read_mode.ReadMode == 1)
else if (alpha_read_mode == PixelEngine::AlphaReadMode::ReadFF)
{
return color | 0xFF000000; // GX_READ_FF
return color | 0xFF000000;
}
else /*if(alpha_read_mode.ReadMode == 0)*/
else
{
return color & 0x00FFFFFF; // GX_READ_00
if (alpha_read_mode != PixelEngine::AlphaReadMode::Read00)
{
PanicAlertFmt("Invalid PE alpha read mode: {}", static_cast<u16>(alpha_read_mode));
}
return color & 0x00FFFFFF;
}
}
else // if (type == EFBAccessType::PeekZ)