Skip to content

Commit

Permalink
Fix blending issues on AMD RX GPUs & optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
LunaTheFoxgirl committed Jun 30, 2023
1 parent edf1e81 commit f41f110
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 51 deletions.
74 changes: 38 additions & 36 deletions source/inochi2d/core/nodes/common.d
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,19 @@ private {
/**
Whether a multi-stage rendering pass should be used for blending
*/
bool inUseMultistageBlending() {
return hasKHRBlendEquationAdvanced;
bool inUseMultistageBlending(BlendMode blendingMode) {
switch(blendingMode) {
case BlendMode.Normal,
BlendMode.LinearDodge,
BlendMode.AddGlow,
BlendMode.Subtract,
BlendMode.Inverse,
BlendMode.DestinationIn,
BlendMode.ClipToLower,
BlendMode.SliceFromLower:
return false;
default: return hasKHRBlendEquationAdvanced;
}
}

void inInitBlending() {
Expand Down Expand Up @@ -201,60 +212,51 @@ enum BlendMode {
SliceFromLower
}

bool inIsAdvancedBlendMode(BlendMode mode) {
if (!inAdvancedBlending) return false;
switch(mode) {
case BlendMode.Multiply:
case BlendMode.Screen:
case BlendMode.Overlay:
case BlendMode.Darken:
case BlendMode.Lighten:
case BlendMode.ColorDodge:
case BlendMode.ColorBurn:
case BlendMode.HardLight:
case BlendMode.SoftLight:
case BlendMode.Difference:
case BlendMode.Exclusion:
return true;

// Fallback to legacy
default:
return false;
}
}

void inSetBlendMode(BlendMode blendingMode, bool legacyOnly=false) {
if (!inAdvancedBlending || legacyOnly) inSetBlendModeLegacy(blendingMode);
else switch(blendingMode) {
case BlendMode.Normal:
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break;

case BlendMode.Multiply: glBlendEquation(GL_MULTIPLY_KHR); break;
case BlendMode.Screen: glBlendEquation(GL_SCREEN_KHR); break;
case BlendMode.Overlay: glBlendEquation(GL_OVERLAY_KHR); break;
case BlendMode.Darken: glBlendEquation(GL_DARKEN_KHR); break;
case BlendMode.Lighten: glBlendEquation(GL_LIGHTEN_KHR); break;
case BlendMode.ColorDodge: glBlendEquation(GL_COLORDODGE_KHR); break;
case BlendMode.LinearDodge:
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break;

case BlendMode.AddGlow:
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break;

case BlendMode.ColorBurn: glBlendEquation(GL_COLORBURN_KHR); break;
case BlendMode.HardLight: glBlendEquation(GL_HARDLIGHT_KHR); break;
case BlendMode.SoftLight: glBlendEquation(GL_SOFTLIGHT_KHR); break;
case BlendMode.Difference: glBlendEquation(GL_DIFFERENCE_KHR); break;
case BlendMode.Exclusion: glBlendEquation(GL_EXCLUSION_KHR); break;

case BlendMode.Subtract:
glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE); break;

case BlendMode.Inverse:
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break;

case BlendMode.DestinationIn:
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ZERO, GL_SRC_ALPHA); break;

case BlendMode.ClipToLower:
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;

case BlendMode.SliceFromLower:
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); break;

// Fallback to legacy
default: inSetBlendModeLegacy(blendingMode); break;
}
}

void inBlendModeBarrier() {
if (inAdvancedBlending && !inAdvancedBlendingCoherent) glBlendBarrierKHR();
void inBlendModeBarrier(BlendMode mode) {
if (inAdvancedBlending && !inAdvancedBlendingCoherent && inIsAdvancedBlendMode(mode))
glBlendBarrierKHR();
}

/**
Expand Down
41 changes: 26 additions & 15 deletions source/inochi2d/core/nodes/part/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private:
case 0:
// STAGE 1 - Advanced blending

glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE].ptr);
glDrawBuffers(1, [GL_COLOR_ATTACHMENT0].ptr);

partShaderStage1.use();
partShaderStage1.setUniform(gs1offset, data.origin);
Expand All @@ -225,23 +225,23 @@ private:
case 1:

// STAGE 2 - Basic blending (albedo, bump)
glDrawBuffers(3, [GL_NONE, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr);
glDrawBuffers(2, [GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr);

partShaderStage2.use();
partShaderStage2.setUniform(gs2offset, data.origin);
partShaderStage2.setUniform(gs2mvp, inGetCamera().matrix * puppet.transform.matrix * matrix);
partShaderStage2.setUniform(gs2opacity, clamp(offsetOpacity * opacity, 0, 1));
partShaderStage2.setUniform(gs2EmissionStrength, emissionStrength*offsetEmissionStrength);

partShaderStage2.setUniform(partShaderStage2.getUniformLocation("emission"), 1);
partShaderStage2.setUniform(partShaderStage2.getUniformLocation("bump"), 2);
partShaderStage2.setUniform(partShaderStage2.getUniformLocation("emission"), 0);
partShaderStage2.setUniform(partShaderStage2.getUniformLocation("bump"), 1);

// These can be reused from stage 2
partShaderStage1.setUniform(gs2MultColor, clampedTint);
partShaderStage1.setUniform(gs2ScreenColor, clampedScreen);
inSetBlendMode(blendingMode, true);
break;
case 3:
case 2:

// Basic blending
glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr);
Expand Down Expand Up @@ -274,7 +274,7 @@ private:

}

void renderStage() {
void renderStage(bool advanced=true)(BlendMode mode) {

// Enable points array
glEnableVertexAttribArray(0);
Expand All @@ -299,8 +299,10 @@ private:
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);

// Blending barrier
inBlendModeBarrier();
static if (advanced) {
// Blending barrier
inBlendModeBarrier(mode);
}
}

/*
Expand Down Expand Up @@ -342,28 +344,37 @@ private:
partMaskShader.setUniform(offset, data.origin);
partMaskShader.setUniform(mmvp, inGetCamera().matrix * puppet.transform.matrix * matrix);
partMaskShader.setUniform(mthreshold, clamp(offsetMaskThreshold + maskAlphaThreshold, 0, 1));

// Make sure the equation is correct
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

renderStage();
renderStage!false(blendingMode);
} else {

if (inUseMultistageBlending()) {
bool hasEmissionOrBumpmap = (textures[1] || textures[2]);

if (inUseMultistageBlending(blendingMode)) {

// TODO: Detect if this Part is NOT in a composite,
// If so, we can relatively safely assume that we may skip stage 1.
setupShaderStage(0, matrix);
renderStage();
setupShaderStage(1, matrix);
renderStage();

renderStage(blendingMode);

// Only do stage 2 if we have emission or bumpmap textures.
if (hasEmissionOrBumpmap) {
setupShaderStage(1, matrix);
renderStage!false(blendingMode);
}
} else {
setupShaderStage(2, matrix);
renderStage();
renderStage!false(blendingMode);
}
}

// Reset draw buffers
glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr);
glBlendEquation(GL_FUNC_ADD);
}

protected:
Expand Down

0 comments on commit f41f110

Please sign in to comment.