tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rrFragmentOperations.js (32843B)


      1 /*-------------------------------------------------------------------------
      2 * drawElements Quality Program OpenGL ES Utilities
      3 * ------------------------------------------------
      4 *
      5 * Copyright 2014 The Android Open Source Project
      6 *
      7 * Licensed under the Apache License, Version 2.0 (the "License");
      8 * you may not use this file except in compliance with the License.
      9 * You may obtain a copy of the License at
     10 *
     11 *      http://www.apache.org/licenses/LICENSE-2.0
     12 *
     13 * Unless required by applicable law or agreed to in writing, software
     14 * distributed under the License is distributed on an "AS IS" BASIS,
     15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16 * See the License for the specific language governing permissions and
     17 * limitations under the License.
     18 *
     19 */
     20 
     21 'use strict';
     22 goog.provide('framework.referencerenderer.rrFragmentOperations');
     23 goog.require('framework.common.tcuTexture');
     24 goog.require('framework.common.tcuTextureUtil');
     25 goog.require('framework.delibs.debase.deMath');
     26 goog.require('framework.referencerenderer.rrRenderState');
     27 
     28 goog.scope(function() {
     29 
     30 var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations;
     31 var deMath = framework.delibs.debase.deMath;
     32 var rrRenderState = framework.referencerenderer.rrRenderState;
     33 var tcuTexture = framework.common.tcuTexture;
     34 var tcuTextureUtil = framework.common.tcuTextureUtil;
     35 
     36 /** Return oldValue with the bits indicated by mask replaced by corresponding bits of newValue.
     37 * @param {number} oldValue
     38 * @param {number} newValue
     39 * @param {number} mask
     40 * @return {number}
     41 */
     42 rrFragmentOperations.maskedBitReplace = function(oldValue, newValue, mask) {
     43    return (oldValue & ~mask) | (newValue & mask);
     44 };
     45 
     46 /**
     47 * @param {Array<number>} point
     48 * @param {?} rect
     49 * @return {boolean}
     50 */
     51 rrFragmentOperations.isInsideRect = function(point, rect) {
     52    return deMath.deInBounds32(point[0], rect.left, rect.left + rect.width) &&
     53           deMath.deInBounds32(point[1], rect.bottom, rect.bottom + rect.height);
     54 };
     55 
     56 /**
     57 * @constructor
     58 * @param {Array<number>} coefficents
     59 * @param {Array<number>} coords
     60 * @param {number} depth
     61 */
     62 rrFragmentOperations.Fragment = function(coefficents, coords, depth) {
     63    /** @type {Array<number>} */ this.barycentric = coefficents;
     64    /** @type {Array<number>} */ this.pixelCoord = coords;
     65    /** @type {boolean} */ this.isAlive = true;
     66    /** @type {boolean} */ this.stencilPassed = true;
     67    /** @type {boolean} */ this.depthPassed = true;
     68    /** @type {Array<number>} */ this.sampleDepths = [depth];
     69    /** @type {Array<number>} */ this.clampedBlendSrcColor = [];
     70    /** @type {Array<number>} */ this.clampedBlendSrc1Color = [];
     71    /** @type {Array<number>} */ this.clampedBlendDstColor = [];
     72    /** @type {Array<number>} */ this.blendSrcFactorRGB = [];
     73    /** @type {number} */ this.blendSrcFactorA = NaN;
     74    /** @type {Array<number>} */ this.blendDstFactorRGB = [];
     75    /** @type {number} */ this.blendDstFactorA = NaN;
     76    /** @type {Array<number>} */ this.blendedRGB = [];
     77    /** @type {number} */ this.blendedA = NaN;
     78    /** @type {Array<number>} */ this.signedValue = []; //!< integer targets
     79    /** @type {Array<number>} */ this.unsignedValue = []; //!< unsigned integer targets
     80    /** @type {Array<number>} */ this.value = []; /*TODO: what type should it be? */
     81    /** @type {Array<number>} */ this.value1 = []; /*TODO: what type should it be? */
     82 };
     83 
     84 /**
     85 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
     86 * @param {rrRenderState.WindowRectangle} scissorRect
     87 */
     88 rrFragmentOperations.executeScissorTest = function(inputFragments, scissorRect) {
     89    for (var i = 0; i < inputFragments.length; i++) {
     90        var frag = inputFragments[i];
     91        if (frag.isAlive) {
     92            if (!rrFragmentOperations.isInsideRect(frag.pixelCoord, scissorRect))
     93                frag.isAlive = false;
     94        }
     95    }
     96 };
     97 
     98 /**
     99 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    100 * @param {rrRenderState.StencilState} stencilState
    101 * @param {number} numStencilBits
    102 * @param {tcuTexture.PixelBufferAccess} stencilBuffer
    103 */
    104 rrFragmentOperations.executeStencilCompare = function(inputFragments, stencilState, numStencilBits, stencilBuffer) {
    105    var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1);
    106 
    107    /**
    108     * @param {function(number=,number=):boolean} expression
    109     */
    110    var sample_register_stencil_compare = function(expression) {
    111        for (var i = 0; i < inputFragments.length; i++) {
    112            var frag = inputFragments[i];
    113            if (frag.isAlive) {
    114                var fragSampleNdx = 0;
    115                var stencilBufferValue = stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    116                var maskedRef = stencilState.compMask & clampedStencilRef;
    117                var maskedBuf = stencilState.compMask & stencilBufferValue;
    118                frag.stencilPassed = expression(maskedRef, maskedBuf);
    119            }
    120        }
    121    };
    122 
    123    switch (stencilState.func) {
    124        case rrRenderState.TestFunc.NEVER: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return false;}); break;
    125        case rrRenderState.TestFunc.ALWAYS: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return true;}); break;
    126        case rrRenderState.TestFunc.LESS: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef < maskedBuf;}); break;
    127        case rrRenderState.TestFunc.LEQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef <= maskedBuf;}); break;
    128        case rrRenderState.TestFunc.GREATER: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef > maskedBuf;}); break;
    129        case rrRenderState.TestFunc.GEQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef >= maskedBuf;}); break;
    130        case rrRenderState.TestFunc.EQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef == maskedBuf;}); break;
    131        case rrRenderState.TestFunc.NOTEQUAL: sample_register_stencil_compare(function(maskedRef, maskedBuf) { return maskedRef != maskedBuf;}); break;
    132        default:
    133            throw new Error('Unrecognized stencil test function:' + stencilState.func);
    134    }
    135 };
    136 
    137 /**
    138 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    139 * @param {rrRenderState.StencilState} stencilState
    140 * @param {number} numStencilBits
    141 * @param {tcuTexture.PixelBufferAccess} stencilBuffer
    142 */
    143 rrFragmentOperations.executeStencilSFail = function(inputFragments, stencilState, numStencilBits, stencilBuffer) {
    144    var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1);
    145    /**
    146     * @param {function(number,number):number} expression
    147     */
    148    var sample_register_sfail = function(expression) {
    149       for (var i = 0; i < inputFragments.length; i++) {
    150            var frag = inputFragments[i];
    151            if (frag.isAlive && !frag.stencilPassed) {
    152                var fragSampleNdx = 0;
    153                var stencilBufferValue = stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    154                stencilBuffer.setPixStencil(rrFragmentOperations.maskedBitReplace(stencilBufferValue, expression(stencilBufferValue, numStencilBits), stencilState.writeMask), fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    155                frag.isAlive = false;
    156            }
    157        }
    158    };
    159 
    160    switch (stencilState.sFail) {
    161        case rrRenderState.StencilOp.KEEP:
    162            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return stencilBufferValue;}); break;
    163        case rrRenderState.StencilOp.ZERO:
    164            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return 0;}); break;
    165        case rrRenderState.StencilOp.REPLACE:
    166            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return clampedStencilRef;}); break;
    167        case rrRenderState.StencilOp.INCR:
    168            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue + 1, 0, (1 << numStencilBits) - 1);}); break;
    169        case rrRenderState.StencilOp.DECR:
    170            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue - 1, 0, (1 << numStencilBits) - 1);}); break;
    171        case rrRenderState.StencilOp.INCR_WRAP:
    172            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return (stencilBufferValue + 1) & ((1 << numStencilBits) - 1);}); break;
    173        case rrRenderState.StencilOp.DECR_WRAP:
    174            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return (stencilBufferValue - 1) & ((1 << numStencilBits) - 1);}); break;
    175        case rrRenderState.StencilOp.INVERT:
    176            sample_register_sfail(function(stencilBufferValue, numStencilBits) { return (~stencilBufferValue) & ((1 << numStencilBits) - 1);}); break;
    177        default:
    178            throw new Error('Unrecognized stencil op:' + stencilState.sFail);
    179    }
    180 
    181 };
    182 
    183 /**
    184 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    185 * @param {rrRenderState.TestFunc} depthFunc
    186 * @param {tcuTexture.PixelBufferAccess} depthBuffer
    187 */
    188 rrFragmentOperations.executeDepthCompare = function(inputFragments, depthFunc, depthBuffer) {
    189    /**
    190     * @param {function(number=,number=):boolean} expression
    191     */
    192    var convertToDepthBuffer = false;
    193 
    194    var access;
    195    if (depthBuffer.getFormat().type != tcuTexture.ChannelType.FLOAT &&
    196        depthBuffer.getFormat().type != tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV) {
    197        access = new tcuTexture.PixelBufferAccess({
    198            format: depthBuffer.getFormat(),
    199            width: 1,
    200            height: 1,
    201            depth: 1,
    202            data: new ArrayBuffer(8)
    203        });
    204        convertToDepthBuffer = true;
    205    }
    206 
    207    var sample_register_depth_compare = function(expression) {
    208      for (var i = 0; i < inputFragments.length; i++) {
    209            var frag = inputFragments[i];
    210            if (frag.isAlive) {
    211                var fragSampleNdx = 0;
    212                var depthBufferValue = depthBuffer.getPixDepth(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    213                var sampleDepthFloat = frag.sampleDepths[fragSampleNdx];
    214 
    215                var sampleDepth;
    216                if (convertToDepthBuffer) {
    217                    /* convert input float to target buffer format for comparison */
    218                    access.setPixDepth(sampleDepthFloat, 0, 0, 0);
    219                    sampleDepth = access.getPixDepth(0, 0, 0);
    220                } else {
    221                    sampleDepth = deMath.clamp(sampleDepthFloat, 0.0, 1.0);
    222                }
    223 
    224                frag.depthPassed = expression(sampleDepth, depthBufferValue);
    225            }
    226        }
    227    };
    228 
    229    switch (depthFunc) {
    230        case rrRenderState.TestFunc.NEVER: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return false;}); break;
    231        case rrRenderState.TestFunc.ALWAYS: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return true;}); break;
    232        case rrRenderState.TestFunc.LESS: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth < depthBufferValue;}); break;
    233        case rrRenderState.TestFunc.LEQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth <= depthBufferValue;}); break;
    234        case rrRenderState.TestFunc.GREATER: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth > depthBufferValue;}); break;
    235        case rrRenderState.TestFunc.GEQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth >= depthBufferValue;}); break;
    236        case rrRenderState.TestFunc.EQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth == depthBufferValue;}); break;
    237        case rrRenderState.TestFunc.NOTEQUAL: sample_register_depth_compare(function(sampleDepth, depthBufferValue) { return sampleDepth != depthBufferValue;}); break;
    238        default:
    239            throw new Error('Unrecognized depth function:' + depthFunc);
    240    }
    241 };
    242 
    243 /**
    244 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    245 * @param {tcuTexture.PixelBufferAccess} depthBuffer
    246 */
    247 rrFragmentOperations.executeDepthWrite = function(inputFragments, depthBuffer) {
    248      for (var i = 0; i < inputFragments.length; i++) {
    249            var frag = inputFragments[i];
    250            if (frag.isAlive && frag.depthPassed) {
    251                var fragSampleNdx = 0;
    252                var clampedDepth = deMath.clamp(frag.sampleDepths[fragSampleNdx], 0.0, 1.0);
    253                depthBuffer.setPixDepth(clampedDepth, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    254            }
    255        }
    256 };
    257 
    258 /**
    259 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    260 * @param {rrRenderState.StencilState} stencilState
    261 * @param {number} numStencilBits
    262 * @param {tcuTexture.PixelBufferAccess} stencilBuffer
    263 */
    264 rrFragmentOperations.executeStencilDpFailAndPass = function(inputFragments, stencilState, numStencilBits, stencilBuffer) {
    265   var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1);
    266 
    267    /**
    268     * @param {function(boolean):boolean} condition
    269     * @param {function(number,number):number} expression
    270     */
    271    var sample_register_dpfail_or_dppass = function(condition, expression) {
    272          for (var i = 0; i < inputFragments.length; i++) {
    273                var frag = inputFragments[i];
    274                if (frag.isAlive && condition(frag.depthPassed)) {
    275                    var fragSampleNdx = 0;
    276                    var stencilBufferValue = stencilBuffer.getPixStencil(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    277                    stencilBuffer.setPixStencil(rrFragmentOperations.maskedBitReplace(stencilBufferValue, expression(stencilBufferValue, numStencilBits), stencilState.writeMask), fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    278                }
    279        }
    280    };
    281 
    282    var switch_dpfail_or_dppass = function(op_name, condition) {
    283        switch (stencilState[op_name]) {
    284            case rrRenderState.StencilOp.KEEP: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return stencilBufferValue;}); break;
    285            case rrRenderState.StencilOp.ZERO: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return 0;}); break;
    286            case rrRenderState.StencilOp.REPLACE: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return clampedStencilRef;}); break;
    287            case rrRenderState.StencilOp.INCR: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue + 1, 0, (1 << numStencilBits) - 1);}); break;
    288            case rrRenderState.StencilOp.DECR: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return deMath.clamp(stencilBufferValue - 1, 0, (1 << numStencilBits) - 1);}); break;
    289            case rrRenderState.StencilOp.INCR_WRAP: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return (stencilBufferValue + 1) & ((1 << numStencilBits) - 1);}); break;
    290            case rrRenderState.StencilOp.DECR_WRAP: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return (stencilBufferValue - 1) & ((1 << numStencilBits) - 1);}); break;
    291            case rrRenderState.StencilOp.INVERT: sample_register_dpfail_or_dppass(condition, function(stencilBufferValue, numStencilBits) { return (~stencilBufferValue) & ((1 << numStencilBits) - 1);}); break;
    292            default:
    293                throw new Error('Unrecognized stencil operation:' + op_name);
    294        }
    295    };
    296 
    297    var passed = function(depthPassed) { return depthPassed;};
    298    var failed = function(depthPassed) { return !depthPassed;};
    299 
    300    switch_dpfail_or_dppass('dpFail', failed);
    301    switch_dpfail_or_dppass('dpPass', passed);
    302 };
    303 
    304 /**
    305 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    306 * @param {Array<number>} blendColor
    307 * @param {rrRenderState.BlendState} blendRGBState
    308 */
    309 rrFragmentOperations.executeBlendFactorComputeRGB = function(inputFragments, blendColor, blendRGBState) {
    310    /**
    311     * @param {string} factor_name
    312     * @param {function(Array<number>, Array<number>, Array<number>):Array<number>} expression
    313     */
    314    var sample_register_blend_factor = function(factor_name, expression) {
    315       for (var i = 0; i < inputFragments.length; i++) {
    316            var frag = inputFragments[i];
    317            if (frag.isAlive) {
    318                var src = frag.clampedBlendSrcColor;
    319                var src1 = frag.clampedBlendSrc1Color;
    320                var dst = frag.clampedBlendDstColor;
    321                frag[factor_name] = deMath.clampVector(expression(src, src1, dst), 0, 1);
    322            }
    323        }
    324    };
    325 
    326    var switch_src_or_dst_factor_rgb = function(func_name, factor_name) {
    327        switch (blendRGBState[func_name]) {
    328            case rrRenderState.BlendFunc.ZERO:
    329                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [0, 0, 0];}); break;
    330            case rrRenderState.BlendFunc.ONE:
    331                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1, 1, 1];}); break;
    332            case rrRenderState.BlendFunc.SRC_COLOR:
    333                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(src, [0, 1, 2]);}); break;
    334            case rrRenderState.BlendFunc.ONE_MINUS_SRC_COLOR:
    335                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(src, [0, 1, 2]));}); break;
    336            case rrRenderState.BlendFunc.DST_COLOR:
    337                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(dst, [0, 1, 2]);}); break;
    338            case rrRenderState.BlendFunc.ONE_MINUS_DST_COLOR:
    339                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(dst, [0, 1, 2]));}); break;
    340            case rrRenderState.BlendFunc.SRC_ALPHA:
    341                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [src[3], src[3], src[3]];}); break;
    342            case rrRenderState.BlendFunc.ONE_MINUS_SRC_ALPHA:
    343                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - src[3], 1.0 - src[3], 1.0 - src[3]];}); break;
    344            case rrRenderState.BlendFunc.DST_ALPHA:
    345                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [dst[3], dst[3], dst[3]];}); break;
    346            case rrRenderState.BlendFunc.ONE_MINUS_DST_ALPHA:
    347                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - dst[3], 1.0 - dst[3], 1.0 - dst[3]];}); break;
    348            case rrRenderState.BlendFunc.CONSTANT_COLOR:
    349                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(blendColor, [0, 1, 2]);}); break;
    350            case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_COLOR:
    351                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(blendColor, [0, 1, 2]));}); break;
    352            case rrRenderState.BlendFunc.CONSTANT_ALPHA:
    353                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [blendColor[3], blendColor[3], blendColor[3]];}); break;
    354            case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_ALPHA:
    355                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - blendColor[3], 1.0 - blendColor[3], 1.0 - blendColor[3]];}); break;
    356            case rrRenderState.BlendFunc.SRC_ALPHA_SATURATE:
    357                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [Math.min(src[3], 1.0 - dst[3]), Math.min(src[3], 1.0 - dst[3]), Math.min(src[3], 1.0 - dst[3])];}); break;
    358            case rrRenderState.BlendFunc.SRC1_COLOR:
    359                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.swizzle(src1, [0, 1, 2]);}); break;
    360            case rrRenderState.BlendFunc.ONE_MINUS_SRC1_COLOR:
    361                sample_register_blend_factor(factor_name, function(src, src1, dst) { return deMath.subtract([1, 1, 1], deMath.swizzle(src1, [0, 1, 2]));}); break;
    362            case rrRenderState.BlendFunc.SRC1_ALPHA:
    363                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [src1[3], src1[3], src1[3]];}); break;
    364            case rrRenderState.BlendFunc.ONE_MINUS_SRC1_ALPHA:
    365                sample_register_blend_factor(factor_name, function(src, src1, dst) { return [1.0 - src1[3], 1.0 - src1[3], 1.0 - src1[3]];}); break;
    366            default:
    367                throw new Error('Unrecognized blend function:' + func_name);
    368            }
    369    };
    370 
    371    switch_src_or_dst_factor_rgb('srcFunc', 'blendSrcFactorRGB');
    372    switch_src_or_dst_factor_rgb('dstFunc', 'blendDstFactorRGB');
    373 
    374 };
    375 
    376 /**
    377 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    378 * @param {Array<number>} blendColor
    379 * @param {rrRenderState.BlendState} blendAState
    380 */
    381 rrFragmentOperations.executeBlendFactorComputeA = function(inputFragments, blendColor, blendAState) {
    382    /**
    383     * @param {string} factor_name
    384     * @param {function(Array<number>, Array<number>, Array<number>):number} expression
    385     */
    386    var sample_register_blend_factor = function(factor_name, expression) {
    387       for (var i = 0; i < inputFragments.length; i++) {
    388            var frag = inputFragments[i];
    389            if (frag.isAlive) {
    390                var src = frag.clampedBlendSrcColor;
    391                var src1 = frag.clampedBlendSrc1Color;
    392                var dst = frag.clampedBlendDstColor;
    393                frag[factor_name] = deMath.clamp(expression(src, src1, dst), 0, 1);
    394            }
    395        }
    396    };
    397 
    398    var swictch_src_or_dst_factor_a = function(func_name, factor_name) {
    399        switch (blendAState[func_name]) {
    400            case rrRenderState.BlendFunc.ZERO:
    401                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 0.0;}); break;
    402            case rrRenderState.BlendFunc.ONE:
    403                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0;}); break;
    404            case rrRenderState.BlendFunc.SRC_COLOR:
    405                sample_register_blend_factor(factor_name, function(src, src1, dst) { return src[3];}); break;
    406            case rrRenderState.BlendFunc.ONE_MINUS_SRC_COLOR:
    407                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src[3];}); break;
    408            case rrRenderState.BlendFunc.DST_COLOR:
    409                sample_register_blend_factor(factor_name, function(src, src1, dst) { return dst[3];}); break;
    410            case rrRenderState.BlendFunc.ONE_MINUS_DST_COLOR:
    411                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - dst[3];}); break;
    412            case rrRenderState.BlendFunc.SRC_ALPHA:
    413                sample_register_blend_factor(factor_name, function(src, src1, dst) { return src[3];}); break;
    414            case rrRenderState.BlendFunc.ONE_MINUS_SRC_ALPHA:
    415                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src[3];}); break;
    416            case rrRenderState.BlendFunc.DST_ALPHA:
    417                sample_register_blend_factor(factor_name, function(src, src1, dst) { return dst[3];}); break;
    418            case rrRenderState.BlendFunc.ONE_MINUS_DST_ALPHA:
    419                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - dst[3];}); break;
    420            case rrRenderState.BlendFunc.CONSTANT_COLOR:
    421                sample_register_blend_factor(factor_name, function(src, src1, dst) { return blendColor[3];}); break;
    422            case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_COLOR:
    423                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - blendColor[3];}); break;
    424            case rrRenderState.BlendFunc.CONSTANT_ALPHA:
    425                sample_register_blend_factor(factor_name, function(src, src1, dst) { return blendColor[3];}); break;
    426            case rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_ALPHA:
    427                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - blendColor[3];}); break;
    428            case rrRenderState.BlendFunc.SRC_ALPHA_SATURATE:
    429                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0;}); break;
    430            case rrRenderState.BlendFunc.SRC1_COLOR:
    431                sample_register_blend_factor(factor_name, function(src, src1, dst) { return src1[3];}); break;
    432            case rrRenderState.BlendFunc.ONE_MINUS_SRC1_COLOR:
    433                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src1[3];}); break;
    434            case rrRenderState.BlendFunc.SRC1_ALPHA:
    435                sample_register_blend_factor(factor_name, function(src, src1, dst) { return src1[3];}); break;
    436            case rrRenderState.BlendFunc.ONE_MINUS_SRC1_ALPHA:
    437                sample_register_blend_factor(factor_name, function(src, src1, dst) { return 1.0 - src1[3];}); break;
    438            default:
    439                throw new Error('Unrecognized blend function:' + func_name);
    440        }
    441    };
    442 
    443    swictch_src_or_dst_factor_a('srcFunc', 'blendSrcFactorA');
    444    swictch_src_or_dst_factor_a('dstFunc', 'blendDstFactorA');
    445 };
    446 
    447 /**
    448 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
    449 * @param {rrRenderState.BlendState} blendRGBState
    450 * @param {rrRenderState.BlendState} blendAState
    451 */
    452 rrFragmentOperations.executeBlend = function(inputFragments, blendRGBState, blendAState) {
    453    var sample_register_blended_color = function(color_name, expression) {
    454       for (var i = 0; i < inputFragments.length; i++) {
    455            var frag = inputFragments[i];
    456            if (frag.isAlive) {
    457                var src = frag.clampedBlendSrcColor;
    458                var dst = frag.clampedBlendDstColor;
    459                frag[color_name] = expression(src, dst, frag);
    460            }
    461        }
    462    };
    463 
    464    switch (blendRGBState.equation) {
    465        case rrRenderState.BlendEquation.ADD:
    466            sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.add(deMath.multiply(deMath.swizzle(src, [0, 1, 2]), frag.blendSrcFactorRGB), deMath.multiply(deMath.swizzle(dst, [0, 1, 2]), frag.blendDstFactorRGB));}); break;
    467        case rrRenderState.BlendEquation.SUBTRACT:
    468            sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.subtract(deMath.multiply(deMath.swizzle(src, [0, 1, 2]), frag.blendSrcFactorRGB), deMath.multiply(deMath.swizzle(dst, [0, 1, 2]), frag.blendDstFactorRGB));}); break;
    469        case rrRenderState.BlendEquation.REVERSE_SUBTRACT:
    470            sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.subtract(deMath.multiply(deMath.swizzle(dst, [0, 1, 2]), frag.blendDstFactorRGB), deMath.multiply(deMath.swizzle(src, [0, 1, 2]), frag.blendSrcFactorRGB));}); break;
    471        case rrRenderState.BlendEquation.MIN:
    472            sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.min(deMath.swizzle(src, [0, 1, 2]), deMath.swizzle(dst, [0, 1, 2]));}); break;
    473        case rrRenderState.BlendEquation.MAX:
    474            sample_register_blended_color('blendedRGB', function(src, dst, frag) { return deMath.max(deMath.swizzle(src, [0, 1, 2]), deMath.swizzle(dst, [0, 1, 2]));}); break;
    475        default:
    476            throw new Error('Unrecognized blend equation:' + blendRGBState.equation);
    477    }
    478 
    479    switch (blendAState.equation) {
    480        case rrRenderState.BlendEquation.ADD:
    481            sample_register_blended_color('blendedA', function(src, dst, frag) { return src[3] * frag.blendSrcFactorA + dst[3] * frag.blendDstFactorA;}); break;
    482        case rrRenderState.BlendEquation.SUBTRACT:
    483            sample_register_blended_color('blendedA', function(src, dst, frag) { return src[3] * frag.blendSrcFactorA - dst[3] * frag.blendDstFactorA;}); break;
    484        case rrRenderState.BlendEquation.REVERSE_SUBTRACT:
    485            sample_register_blended_color('blendedA', function(src, dst, frag) { return dst[3] * frag.blendDstFactorA - src[3] * frag.blendSrcFactorA;}); break;
    486        case rrRenderState.BlendEquation.MIN:
    487            sample_register_blended_color('blendedA', function(src, dst, frag) { return Math.min(src[3], dst[3]);}); break;
    488        case rrRenderState.BlendEquation.MAX:
    489            sample_register_blended_color('blendedA', function(src, dst, frag) { return Math.max(src[3], dst[3]);}); break;
    490        default:
    491            throw new Error('Unrecognized blend equation:' + blendAState.equation);
    492    }
    493 };
    494 
    495 /**
    496 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
    497 * @param {boolean} isSRGB
    498 * @param {tcuTexture.PixelBufferAccess} colorBuffer
    499 */
    500 rrFragmentOperations.executeColorWrite = function(inputFragments, isSRGB, colorBuffer) {
    501       for (var i = 0; i < inputFragments.length; i++) {
    502            var frag = inputFragments[i];
    503            if (frag.isAlive) {
    504                var combinedColor = frag.blendedRGB.slice();
    505                combinedColor[3] = frag.blendedA;
    506                if (isSRGB)
    507                    combinedColor = tcuTextureUtil.linearToSRGB(combinedColor);
    508 
    509                colorBuffer.setPixel(combinedColor, 0, frag.pixelCoord[0], frag.pixelCoord[1]);
    510        }
    511    }
    512 };
    513 
    514 /**
    515 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
    516 * @param {Array<boolean>} colorMaskFactor
    517 * @param {Array<boolean>} colorMaskNegationFactor
    518 * @param {boolean} isSRGB
    519 * @param {tcuTexture.PixelBufferAccess} colorBuffer
    520 */
    521 rrFragmentOperations.executeMaskedColorWrite = function(inputFragments, colorMaskFactor, colorMaskNegationFactor, isSRGB, colorBuffer) {
    522       for (var i = 0; i < inputFragments.length; i++) {
    523            var frag = inputFragments[i];
    524            if (frag.isAlive) {
    525                var fragSampleNdx = 0;
    526                var originalColor = colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    527                var newColor = frag.blendedRGB.slice();
    528                newColor[3] = frag.blendedA;
    529 
    530                if (isSRGB)
    531                    newColor = tcuTextureUtil.linearToSRGB(newColor);
    532 
    533                newColor = deMath.add(deMath.multiply(colorMaskFactor, newColor), deMath.multiply(colorMaskNegationFactor, originalColor));
    534 
    535                colorBuffer.setPixel(newColor, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    536            }
    537        }
    538 };
    539 
    540 /**
    541 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
    542 * @param {Array<boolean>} colorMask
    543 * @param {tcuTexture.PixelBufferAccess} colorBuffer
    544 */
    545 rrFragmentOperations.executeSignedValueWrite = function(inputFragments, colorMask, colorBuffer) {
    546      for (var i = 0; i < inputFragments.length; i++) {
    547            var frag = inputFragments[i];
    548            if (frag.isAlive) {
    549                var fragSampleNdx = 0;
    550                var originalValue = colorBuffer.getPixelInt(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    551                var newValue = tcuTextureUtil.select(frag.signedValue, originalValue, colorMask);
    552 
    553                colorBuffer.setPixelInt(newValue, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    554            }
    555        }
    556 };
    557 
    558 /**
    559 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
    560 * @param {Array<boolean>} colorMask
    561 * @param {tcuTexture.PixelBufferAccess} colorBuffer
    562 */
    563 rrFragmentOperations.executeUnsignedValueWrite = function(inputFragments, colorMask, colorBuffer) {
    564      for (var i = 0; i < inputFragments.length; i++) {
    565            var frag = inputFragments[i];
    566            if (frag.isAlive) {
    567                var fragSampleNdx = 0;
    568                var originalValue = colorBuffer.getPixelInt(fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    569                var newValue = tcuTextureUtil.select(frag.unsignedValue, originalValue, colorMask);
    570 
    571                colorBuffer.setPixelInt(newValue, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
    572            }
    573        }
    574 };
    575 
    576 /**
    577 * @constructor
    578 */
    579 rrFragmentOperations.FragmentProcessor = function() {
    580    /* TODO: implement */
    581 };
    582 
    583 });