void GGLAssembler::build_blend_factor( integer_t& factor, int f, int component, const pixel_t& dst_pixel, integer_t& fragment, integer_t& fb, Scratch& scratches) { integer_t src_alpha(fragment); // src_factor/dst_factor won't be used after blending, // so it's fine to mark them as CORRUPTIBLE (if not aliased) factor.flags |= CORRUPTIBLE; switch(f) { case GGL_ONE_MINUS_SRC_ALPHA: case GGL_SRC_ALPHA: if (component==GGLFormat::ALPHA && !isAlphaSourceNeeded()) { // we're processing alpha, so we already have // src-alpha in fragment, and we need src-alpha just this time. } else { // alpha-src will be needed for other components if (!mBlendFactorCached || mBlendFactorCached==f) { src_alpha = mAlphaSource; factor = mAlphaSource; factor.flags &= ~CORRUPTIBLE; // we already computed the blend factor before, nothing to do. if (mBlendFactorCached) return; // this is the first time, make sure to compute the blend // factor properly. mBlendFactorCached = f; break; } else { // we have a cached alpha blend factor, but we want another one, // this should really not happen because by construction, // we cannot have BOTH source and destination // blend factors use ALPHA *and* ONE_MINUS_ALPHA (because // the blending stage uses the f/(1-f) optimization // for completeness, we handle this case though. Since there // are only 2 choices, this meens we want "the other one" // (1-factor) factor = mAlphaSource; factor.flags &= ~CORRUPTIBLE; RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s))); mBlendFactorCached = f; return; } } // fall-through... case GGL_ONE_MINUS_DST_COLOR: case GGL_DST_COLOR: case GGL_ONE_MINUS_SRC_COLOR: case GGL_SRC_COLOR: case GGL_ONE_MINUS_DST_ALPHA: case GGL_DST_ALPHA: case GGL_SRC_ALPHA_SATURATE: // help us find out what register we can use for the blend-factor // CORRUPTIBLE registers are chosen first, or a new one is allocated. if (fragment.flags & CORRUPTIBLE) { factor.setTo(fragment.reg, 32, CORRUPTIBLE); fragment.flags &= ~CORRUPTIBLE; } else if (fb.flags & CORRUPTIBLE) { factor.setTo(fb.reg, 32, CORRUPTIBLE); fb.flags &= ~CORRUPTIBLE; } else { factor.setTo(scratches.obtain(), 32, CORRUPTIBLE); } break; } // XXX: doesn't work if size==1 switch(f) { case GGL_ONE_MINUS_DST_COLOR: case GGL_DST_COLOR: factor.s = fb.s; ADD(AL, 0, factor.reg, fb.reg, reg_imm(fb.reg, LSR, fb.s-1)); break; case GGL_ONE_MINUS_SRC_COLOR: case GGL_SRC_COLOR: factor.s = fragment.s; ADD(AL, 0, factor.reg, fragment.reg, reg_imm(fragment.reg, LSR, fragment.s-1)); break; case GGL_ONE_MINUS_SRC_ALPHA: case GGL_SRC_ALPHA: factor.s = src_alpha.s; ADD(AL, 0, factor.reg, src_alpha.reg, reg_imm(src_alpha.reg, LSR, src_alpha.s-1)); break; case GGL_ONE_MINUS_DST_ALPHA: case GGL_DST_ALPHA: // XXX: should be precomputed extract(factor, dst_pixel, GGLFormat::ALPHA); ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1)); break; case GGL_SRC_ALPHA_SATURATE: // XXX: should be precomputed // XXX: f = min(As, 1-Ad) // btw, we're guaranteed that Ad's size is <= 8, because // it's extracted from the framebuffer break; } switch(f) { case GGL_ONE_MINUS_DST_COLOR: case GGL_ONE_MINUS_SRC_COLOR: case GGL_ONE_MINUS_DST_ALPHA: case GGL_ONE_MINUS_SRC_ALPHA: RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s))); } // don't need more than 8-bits for the blend factor // and this will prevent overflows in the multiplies later if (factor.s > 8) { MOV(AL, 0, factor.reg, reg_imm(factor.reg, LSR, factor.s-8)); factor.s = 8; } }