bloom2 wip

This commit is contained in:
Jasper St. Pierre
2026-04-13 01:29:12 -07:00
parent 7580cce803
commit a14fe187b9
2 changed files with 144 additions and 73 deletions
+3
View File
@@ -31,6 +31,9 @@ public:
void create();
void remove();
void draw();
#if TARGET_PC
void draw2();
#endif
u8 getEnable() { return mEnable; }
void setEnable(u8 i_enable) { mEnable = i_enable; }
+141 -73
View File
@@ -1258,7 +1258,6 @@ void mDoGph_gInf_c::bloom_c::remove() {
mMonoColor.a = 0;
}
#if TARGET_PC
static void CopyToTexObj(GXTexObj* pDst, uintptr_t texID, int dstWidth, int dstHeight, GXTexFmt dstFmt = GX_TF_RGBA8) {
GXSetTexCopyDst(dstWidth, dstHeight, dstFmt, FALSE);
@@ -1267,11 +1266,11 @@ static void CopyToTexObj(GXTexObj* pDst, uintptr_t texID, int dstWidth, int dstH
GXInitTexObjLOD(pDst, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
}
void mDoGph_gInf_c::bloom_c::draw() {
void mDoGph_gInf_c::bloom_c::draw2() {
ZoneScoped;
if (!dusk::getSettings().game.enableBloom) {
return;
}
// if (!dusk::getSettings().game.enableBloom) {
// return;
// }
bool enabled = mEnable;
if (mMonoColor.a == 0 && !enabled)
@@ -1279,13 +1278,11 @@ void mDoGph_gInf_c::bloom_c::draw() {
f32 width = mDoGph_gInf_c::getWidth();
f32 height = mDoGph_gInf_c::getHeight();
GXSetViewport(0.0f, 0.0f, width, height, 0.0f, 1.0f);
GXSetScissor(0, 0, width, height);
GXLoadTexObj(getFrameBufferTexObj(), GX_TEXMAP0);
GXSetNumChans(0);
GXSetNumTexGens(1);
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c);
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_GREEN);
GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA);
GXSetZCompLoc(1);
@@ -1296,7 +1293,7 @@ void mDoGph_gInf_c::bloom_c::draw() {
GXSetCullMode(GX_CULL_NONE);
GXSetDither(1);
Mtx44 ortho;
C_MTXOrtho(ortho, 0.0f, height, 0.0f, width, 0.0f, 10.0f);
C_MTXOrtho(ortho, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f);
GXLoadPosMtxImm(cMtx_getIdentity(), 0);
GXSetProjection(ortho, GX_ORTHOGRAPHIC);
GXSetCurrentMtx(0);
@@ -1306,16 +1303,51 @@ void mDoGph_gInf_c::bloom_c::draw() {
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S8, 0);
auto filterQuad = [&](int div) {
f32 x = width / div, y = height / div;
// Set up viewports for our pyramid.
enum { MaxDivNum = 10 };
enum {
Pass0,
FinalPass,
BlurPass0, BlurPassN = BlurPass0 + MaxDivNum,
MaxTexNum,
};
scissor_class divPorts[MaxDivNum];
divPorts[0] = {0.0f, 0.0f, 1.0f, 1.0f}; // full-size texture
divPorts[1] = {0.0f, 0.0f, 0.5f, 0.5f}; // bloom texture (wide enough, half-tall)
divPorts[2] = {0.5f, 0.0f, 0.25f, 0.25f};
for (int i = 3; i < ARRAY_SIZE(divPorts); i++) {
auto& port = divPorts[i];
auto const& prev = divPorts[i - 1];
port.x_orig = prev.x_orig;
port.y_orig = prev.y_orig + prev.height;
port.width = prev.width * 0.5f;
port.height = prev.height * 0.5f;
}
auto divCopySrc = [&](int divNo) {
auto const& port = divPorts[divNo];
GXSetTexCopySrc(port.x_orig * width, port.y_orig * height, port.width * width, port.height * height);
};
TGXTexObj tmpTex[MaxTexNum];
auto divCopyTex = [&](uintptr_t texNo, int divNo) -> GXTexObj * {
auto const& port = divPorts[divNo];
CopyToTexObj(&tmpTex[texNo], texNo, port.width * width, port.height * height);
return &tmpTex[texNo];
};
auto divQuad = [&](int divNo) {
auto const& port = divPorts[divNo];
f32 x0 = port.x_orig, y0 = port.y_orig;
f32 x1 = x0 + port.width, y1 = y0 + port.height;
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
GXPosition3f32(0, 0, -5);
GXPosition3f32(x0, y0, -5);
GXTexCoord2s8(0, 0);
GXPosition3f32(x, 0, -5);
GXPosition3f32(x1, y0, -5);
GXTexCoord2s8(1, 0);
GXPosition3f32(x, y, -5);
GXPosition3f32(x1, y1, -5);
GXTexCoord2s8(1, 1);
GXPosition3f32(0, y, -5);
GXPosition3f32(x0, y1, -5);
GXTexCoord2s8(0, 1);
GXEnd();
};
@@ -1330,13 +1362,12 @@ void mDoGph_gInf_c::bloom_c::draw() {
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP1, GX_TEV_SWAP1);
GXSetTevColor(GX_TEVREG2, mMonoColor);
GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_OR);
filterQuad(1);
divQuad(0);
}
if (enabled) {
enum PassID { Pass0, Pass1, Pass2 };
GXCreateFrameBuffer(width, height);
GXCreateFrameBuffer(width * 0.75f, height * 0.5f);
GXSetViewport(0.0f, 0.0f, width, height, 0.1f, 1.0f); // use oversized viewport to make the math easier
GXSetNumTevStages(3);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
@@ -1359,75 +1390,96 @@ void mDoGph_gInf_c::bloom_c::draw() {
GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_OR);
GXColorS10 tevColor0 = {(s16)-mPoint, (s16)-mPoint, (s16)-mPoint, 0x40};
GXSetTevColorS10(GX_TEVREG0, tevColor0);
GXColor tevColor1 = {mBlureRatio, mBlureRatio, mBlureRatio, mBlureRatio};
GXSetTevColor(GX_TEVREG1, tevColor1);
GXPixModeSync();
filterQuad(2);
// Create thresholded 1/2 image.
divQuad(1);
GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA);
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
// Downsample and filter from 1/2 EFB into 1/4.
TGXTexObj tmpTex[3];
GXSetTexCopySrc(0, 0, width / 2, height / 2);
CopyToTexObj(&tmpTex[0], Pass0, width / 4, height / 4);
GXLoadTexObj(&tmpTex[0], GX_TEXMAP0);
divCopySrc(1);
GXTexObj* texPass0 = divCopyTex(Pass0, 2);
GXLoadTexObj(texPass0, GX_TEXMAP0);
f32 blurScale = mBlureSize * ((448.0f / getHeight()) / 6400.0f);
// Setup blur filter TEV.
GXSetNumTexGens(8);
u32 texMtxID = GX_TEXMTX0;
int angle = 0;
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
for (int texCoord = (int)GX_TEXCOORD1; texCoord < (int)GX_MAX_TEXCOORD; texCoord++) {
GXSetTexCoordGen((GXTexCoordID)texCoord, GX_TG_MTX2x4, GX_TG_TEX0, texMtxID);
f32 dVar15 = mBlureSize * ((448.0f / getHeight()) / 6400.0f);
mDoMtx_stack_c::transS((dVar15 * cM_scos(angle)) * getInvScale(),
dVar15 * cM_ssin(angle), 0.0f);
GXLoadTexMtxImm(mDoMtx_stack_c::get(), texMtxID, GX_MTX2x4);
texMtxID += 3;
angle += 0x2492;
}
auto SetupBlurMtx = [](float scale) {
u32 texMtxID = GX_TEXMTX0;
int angle = 0;
for (int texCoord = (int)GX_TEXCOORD0; texCoord < (int)GX_MAX_TEXCOORD; texCoord++) {
GXSetTexCoordGen((GXTexCoordID)texCoord, GX_TG_MTX2x4, GX_TG_TEX0, texMtxID);
mDoMtx_stack_c::transS((scale * cM_scos(angle)) * getInvScale(),
scale * cM_ssin(angle), 0.0f);
GXLoadTexMtxImm(mDoMtx_stack_c::get(), texMtxID, GX_MTX2x4);
texMtxID += 3;
angle += 0x2000;
}
};
GXSetNumTevStages(8);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A1, GX_CC_ZERO);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
for (int tevStage = (int)GX_TEVSTAGE1; tevStage < 8; tevStage++) {
GXSetTevOrder((GXTevStageID)tevStage, (GXTexCoordID)tevStage, GX_TEXMAP0,
GX_COLOR_NULL);
GXSetTevColorIn((GXTevStageID)tevStage, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A1, GX_CC_CPREV);
GXSetTevColorOp((GXTevStageID)tevStage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
GX_TEVPREV);
GXSetTevAlphaIn((GXTevStageID)tevStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
GXSetTevAlphaOp((GXTevStageID)tevStage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
GX_TEVPREV);
for (int stage = 0; stage < 8; stage++) {
GXTevStageID tevStage = (GXTevStageID)stage;
GXSetTevOrder(tevStage, (GXTexCoordID)stage, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevColorIn(tevStage, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A1, stage == 0 ? GX_CC_ZERO : GX_CC_CPREV);
GXSetTevColorOp(tevStage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(tevStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
GXSetTevAlphaOp(tevStage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
}
GXPixModeSync();
// Blur filter from tmp_tex1 1/4 to EFB 1/4.
filterQuad(4);
// Successively downsample and apply blurs.
int divStart = 2;
int divNum = 6;
GXSetTexCopySrc(0, 0, width / 4, height / 4);
CopyToTexObj(&tmpTex[1], Pass1, width / 8, height / 8);
GXLoadTexObj(&tmpTex[1], GX_TEXMAP0);
// Distribute the brightness through each pass.
int totalNumPasses = (divNum - divStart) * 2; // down, up
float brightnessF32 = (mBlureRatio / 255.0f);
float brightnessPerPass = 255.0f * powf(brightnessF32, 1.0f / totalNumPasses);
GXSetTevColorS10(GX_TEVREG1, {0, 0, 0, s16(brightnessPerPass / 8)});
// Upsample 1/8 buffer back up to 1/4 buffer.
GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_OR);
GXPixModeSync();
GXInvalidateTexAll();
filterQuad(4);
for (int i = divStart; i < divNum; i++) {
float blurStrength = 1.0f + (i - divStart) * 5.0f;
SetupBlurMtx(blurScale * blurStrength);
// Apply blur filter.
divQuad(i);
// Copy to next layer.
divCopySrc(i);
// Set up for the next pass down.
GXTexObj * blurTex = divCopyTex(BlurPass0 + i, i + 1);
GXLoadTexObj(blurTex, GX_TEXMAP0);
}
// All the way down at the bottom. Instead of blurring the bottom layer by itself, we blur when going up to the next layer.
// The remaining upscales are all just normal alpha blending.
divQuad(divNum);
// Now successively alpha blend back up, don't blur anymore.
GXSetNumTevStages(1);
GXSetTevColorS10(GX_TEVREG1, {0, 0, 0, s16(brightnessPerPass)});
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_OR);
for (int i = divNum; i > divStart; i--) {
divCopySrc(i);
GXTexObj* upTex = divCopyTex(BlurPass0 + i, i);
GXLoadTexObj(upTex, GX_TEXMAP0);
divQuad(i - 1);
}
// Now that we've upsampled and filtered our final bloom, copy 1/4 buffer.
GXSetTexCopySrc(0, 0, width / 4, height / 4);
CopyToTexObj(&tmpTex[2], Pass2, width / 4, height / 4);
GXLoadTexObj(&tmpTex[2], GX_TEXMAP0);
divCopySrc(2);
GXTexObj* texFinal = divCopyTex(FinalPass, 2);
GXLoadTexObj(texFinal, GX_TEXMAP0);
GXRestoreFrameBuffer();
GXSetViewport(0.0f, 0.0f, width, height, 0.0f, 1.0f);
// Now blend our bloom into the real FB.
GXSetTevColor(GX_TEVREG0, mBlendColor);
@@ -1437,14 +1489,27 @@ void mDoGph_gInf_c::bloom_c::draw() {
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetBlendMode(GX_BM_BLEND, mMode == 1 ? GX_BL_INVDSTCLR : GX_BL_ONE, GX_BL_SRCALPHA, GX_LO_OR);
GXSetBlendMode(GX_BM_BLEND, mMode == 1 ? GX_BL_INVDSTCLR : GX_BL_ONE, GX_BL_SRCALPHA,
GX_LO_OR);
GXPixModeSync();
GXInvalidateTexAll();
filterQuad(1);
divQuad(0);
}
}
#else
#endif
void mDoGph_gInf_c::bloom_c::draw() {
ZoneScoped;
if (!dusk::getSettings().game.enableBloom) {
return;
}
static bool s_bloom2 = false;
if (s_bloom2) {
draw2();
return;
}
bool enabled = mEnable && m_buffer != NULL;
if (mMonoColor.a != 0 || enabled) {
#if TARGET_PC
@@ -1563,8 +1628,12 @@ void mDoGph_gInf_c::bloom_c::draw() {
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
for (int texCoord = (int)GX_TEXCOORD1; texCoord < (int)GX_MAX_TEXCOORD; texCoord++) {
GXSetTexCoordGen((GXTexCoordID)texCoord, GX_TG_MTX2x4, GX_TG_TEX0, texMtxID);
#if TARGET_PC
f32 dVar15 = mBlureSize * ((448.0f / height) / 6400.0f);
#else
f32 dVar15 = mBlureSize * (1.0f / 6400.0f);
#endif
mDoMtx_stack_c::transS((dVar15 * cM_scos(angle)) * getInvScale(),
dVar15 * cM_ssin(angle), 0.0f);
@@ -1673,7 +1742,6 @@ void mDoGph_gInf_c::bloom_c::draw() {
}
}
}
#endif
static void retry_captue_frame(view_class* param_0, view_port_class* param_1, int param_2) {
UNUSED(param_0);