[graphite] Refactor colortype/format optimization function TextureFormatXferFn.cpp There are many more optimizations that can be applied inside the new optimize_transfer function, but they need to be able to manipulate more parameters (such as the swizzle and color space), and have control over the final ops. Sometimes they also need to know the direction of the transfer. This is a cosmetic change that sets up the function for later expansion. Bug: 509890794 Change-Id: I3b26c6b73b6d92faa0d1a2078e2d07d3276ae3ef Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1342696 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Reviewed-by: Thomas Smith <thomsmit@google.com>
diff --git a/src/gpu/graphite/TextureFormatXferFn.cpp b/src/gpu/graphite/TextureFormatXferFn.cpp index 969f5be..eb30e8f 100644 --- a/src/gpu/graphite/TextureFormatXferFn.cpp +++ b/src/gpu/graphite/TextureFormatXferFn.cpp
@@ -288,44 +288,7 @@ } } -void optimize_colortypes_and_swizzle(SkColorType* texBaseCT, Swizzle* readSwizzle) { - // Some combinations of swizzle and load/store ops in raster pipeline are redundant so try to - // make adjustments to reduce or eliminate the use of raster pipeline entirely. - - // The most trivial cases are swizzling between alpha-only and red-only color types which should - // be a no-op in either direction as long as the underlying data type is the same. These - // also test the forced-opaque swizzle equivalents. - SkColorType adjustedBase = *texBaseCT; - if (*readSwizzle == Swizzle("000r") || *readSwizzle == Swizzle("0001")) { - // Red -> Alpha so shift the texture's "base" colortype to be the corresponding alpha type - switch(adjustedBase) { - case kR8_unorm_SkColorType: adjustedBase = kAlpha_8_SkColorType; break; - case kR16_unorm_SkColorType: adjustedBase = kA16_unorm_SkColorType; break; - case kR16_float_SkColorType: adjustedBase = kA16_float_SkColorType; break; - default: break; // Go through regular RP + swizzle flow - } - } else if ((*readSwizzle == Swizzle("rrra") || *readSwizzle == Swizzle("rrr1")) && - adjustedBase == kR8_unorm_SkColorType) { - // Red -> Gray so shift to kGray, which either ensures RP will generate the gray values from - // a non-gray input, or will be detected as a no-op when transferring to/from existing gray. - adjustedBase = kGray_8_SkColorType; - } - - // TODO(michaelludwig): Include adjustments to account for redundant RB swaps between colortype - // and the swizzle and the FormatXferOp, and remove unnecessary alpha opacity masking (e.g. - // rgbx -> rgba) if the target will be masking alpha when sampling/reading anyways. - - if (adjustedBase != *texBaseCT) { - *texBaseCT = adjustedBase; - // Must preserve any forced opacity in the swizzle - if ((SkColorTypeChannelFlags(adjustedBase) & kAlpha_SkColorChannelFlag) && - (*readSwizzle)[3] == '1') { - *readSwizzle = Swizzle::RGB1(); - } else { - *readSwizzle = Swizzle::RGBA(); - } - } -} +// --- Functions for collapsing equivalent colortypes and formats into fewer xfer ops // An RPModifier for RPOps::Make() that handles calculating bt709 luminance. The API is that it // must have an explicit bool operator, and an apply(SkRasterPipeline*) function. @@ -341,10 +304,10 @@ }; bool account_for_luminance(SkColorType srcCT, - const SkColorSpaceXformSteps& cs, + bool hasColorSpaceTransform, SkColorType* dstCT) { if (*dstCT == kGray_8_SkColorType) { - if (srcCT != kGray_8_SkColorType || SkToBool(cs)) { + if (srcCT != kGray_8_SkColorType || hasColorSpaceTransform) { // Luminance must be calculated by raster pipeline, but we'll have to apply it before // any srcToDst swizzle, so pull it out to its own RPModifier. The op stores the value // in the alpha channel, so that needs to be dstCT that SkRasterPipeline sees. @@ -355,6 +318,76 @@ return false; } +template <bool TextureIsDst> +std::pair</*ops=*/uint8_t, /*computeLuminance=*/bool> optimize_transfer( + SkColorType* cpuCT, + SkColorType* texBaseCT, + Swizzle* texReadSwizzle, + SkColorSpaceXformSteps* csSteps, + SkEnumBitMask<FormatXferOp> xferOps) { + // Aliases for color types that are based on the transfer direction + SkColorType* srcCT = TextureIsDst ? cpuCT : texBaseCT; + SkColorType* dstCT = TextureIsDst ? texBaseCT : cpuCT; + + uint8_t finalOps = 0; + + // Some combinations of swizzle and load/store ops in raster pipeline are redundant so try to + // make adjustments to reduce or eliminate the use of raster pipeline entirely. + + // First, adjust texBaseCT to match colortype semantics that can be inferred from swizzle for + // alpha-only and red-only color types (hopefully creating a no-op transfer). These also test + // the forced-opaque swizzle equivalents. + { + SkColorType adjustedBase = *texBaseCT; + if (*texReadSwizzle == Swizzle("000r") || *texReadSwizzle == Swizzle("0001")) { + // Red -> Alpha so shift the texture's "base" colortype to be the its alpha type + switch(adjustedBase) { + case kR8_unorm_SkColorType: adjustedBase = kAlpha_8_SkColorType; break; + case kR16_unorm_SkColorType: adjustedBase = kA16_unorm_SkColorType; break; + case kR16_float_SkColorType: adjustedBase = kA16_float_SkColorType; break; + default: break; // Go through regular RP + swizzle flow + } + } else if ((*texReadSwizzle == Swizzle("rrra") || *texReadSwizzle == Swizzle("rrr1")) && + adjustedBase == kR8_unorm_SkColorType) { + // Red -> Gray so shift to kGray, which either ensures RP will generate the gray values + // from a non-gray input, or will be detected as a no-op when transferring to/from + // existing gray. + adjustedBase = kGray_8_SkColorType; + } + + if (adjustedBase != *texBaseCT) { + *texBaseCT = adjustedBase; + // Must preserve any forced opacity in the swizzle + if ((SkColorTypeChannelFlags(adjustedBase) & kAlpha_SkColorChannelFlag) && + (*texReadSwizzle)[3] == '1') { + *texReadSwizzle = Swizzle::RGB1(); + } else { + *texReadSwizzle = Swizzle::RGBA(); + } + } + } + + // TODO(michaelludwig): Include adjustments to account for redundant RB swaps between colortype + // and the swizzle and the FormatXferOp, and remove unnecessary alpha opacity masking (e.g. + // rgbx -> rgba) if the target will be masking alpha when sampling/reading anyways. + + const bool computeLuminance = account_for_luminance(*srcCT, SkToBool(*csSteps), dstCT); + + if (xferOps & FormatXferOp::kSwapRB) { + finalOps |= kSwapRB; + } + if (xferOps & FormatXferOp::kDropAlpha) { + if constexpr (TextureIsDst) { + // On CPU->GPU conversion, FormatXferOp::kDropAlpha actually drops the alpha bits + finalOps |= kDropAlpha; + } else { + finalOps |= kPadAlpha; + } + } + + return {finalOps, computeLuminance}; +} + } // anonymous namespace std::optional<TextureFormatXferFn> TextureFormatXferFn::MakeCpuToGpu( @@ -367,19 +400,9 @@ return std::nullopt; } - optimize_colortypes_and_swizzle(&baseCT, &dstReadSwizzle); - const bool computeLuminance = account_for_luminance(srcCT, csSteps, &baseCT); - - uint8_t postOps = 0; - Swizzle srcToDst = dstReadSwizzle.invert(); - - if (xferOps & FormatXferOp::kSwapRB) { - postOps |= kSwapRB; - } - if (xferOps & FormatXferOp::kDropAlpha) { - // On CPU->GPU conversion, FormatXferOp::kDropAlpha actually drops the alpha bits - postOps |= kDropAlpha; - } + SkColorSpaceXformSteps csStepsOptimized = csSteps; + auto [postOps, luminance] = optimize_transfer</*TextureIsDst=*/true>( + &srcCT, &baseCT, &dstReadSwizzle, &csStepsOptimized, xferOps); // The CPU -> GPU transform is: // SkRP{load(srcCT) -> @@ -388,7 +411,8 @@ // srcToDst(dstReadSwizzle^-1)? -> // store(baseCT)}? -> // postOps(baseCT->TF)? - auto rp = RPOps::Make(srcCT, baseCT, csSteps, BT709Luminance{computeLuminance}, srcToDst); + auto rp = RPOps::Make(srcCT, baseCT, // ==> rpModifiers + csStepsOptimized, BT709Luminance{luminance}, dstReadSwizzle.invert()); return TextureFormatXferFn(dstFormat, /*preOps=*/0, std::move(rp), postOps); } @@ -402,18 +426,9 @@ return std::nullopt; } - optimize_colortypes_and_swizzle(&baseCT, &srcReadSwizzle); - const bool computeLuminance = account_for_luminance(baseCT, csSteps, &dstCT); - - uint8_t preOps = 0; - Swizzle srcToDst = srcReadSwizzle; - if (xferOps & FormatXferOp::kSwapRB) { - preOps |= kSwapRB; - } - if (xferOps & FormatXferOp::kDropAlpha) { - // On GPU->CPU conversion, FormatXferOp::kDropAlpha must pad alpha bits back - preOps |= kPadAlpha; - } + SkColorSpaceXformSteps csStepsOptimized = csSteps; + auto [preOps, luminance] = optimize_transfer</*TextureIsDst=*/false>( + &dstCT, &baseCT, &srcReadSwizzle, &csStepsOptimized, xferOps); // The GPU -> CPU transform is: // preOps(TF->baseCT)? -> @@ -422,7 +437,8 @@ // csSteps? -> // luminance? -> // store(dstCT)}? - auto rp = RPOps::Make(baseCT, dstCT, srcToDst, csSteps, BT709Luminance{computeLuminance}); + auto rp = RPOps::Make(baseCT, dstCT, // ==> rpModifiers + srcReadSwizzle, csStepsOptimized, BT709Luminance{luminance}); return TextureFormatXferFn(srcFormat, preOps, std::move(rp), /*postOps=*/0); }