Bug 1918529 - fix some subpixel misalignment issues with gfx.webrender.svg-filter...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / framework / referencerenderer / rrFragmentOperations.js
bloba9c2a1f4643dcf83b8f9e1c56d9b07a08bf4b418
1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
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');
28 goog.scope(function() {
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;
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}
42 rrFragmentOperations.maskedBitReplace = function(oldValue, newValue, mask) {
43 return (oldValue & ~mask) | (newValue & mask);
46 /**
47 * @param {Array<number>} point
48 * @param {?} rect
49 * @return {boolean}
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);
56 /**
57 * @constructor
58 * @param {Array<number>} coefficents
59 * @param {Array<number>} coords
60 * @param {number} depth
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? */
84 /**
85 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
86 * @param {rrRenderState.WindowRectangle} scissorRect
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;
98 /**
99 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
100 * @param {rrRenderState.StencilState} stencilState
101 * @param {number} numStencilBits
102 * @param {tcuTexture.PixelBufferAccess} stencilBuffer
104 rrFragmentOperations.executeStencilCompare = function(inputFragments, stencilState, numStencilBits, stencilBuffer) {
105 var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1);
108 * @param {function(number=,number=):boolean} expression
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);
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);
138 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
139 * @param {rrRenderState.StencilState} stencilState
140 * @param {number} numStencilBits
141 * @param {tcuTexture.PixelBufferAccess} stencilBuffer
143 rrFragmentOperations.executeStencilSFail = function(inputFragments, stencilState, numStencilBits, stencilBuffer) {
144 var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1);
146 * @param {function(number,number):number} expression
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;
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);
184 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
185 * @param {rrRenderState.TestFunc} depthFunc
186 * @param {tcuTexture.PixelBufferAccess} depthBuffer
188 rrFragmentOperations.executeDepthCompare = function(inputFragments, depthFunc, depthBuffer) {
190 * @param {function(number=,number=):boolean} expression
192 var convertToDepthBuffer = false;
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)
204 convertToDepthBuffer = true;
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];
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);
224 frag.depthPassed = expression(sampleDepth, depthBufferValue);
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);
244 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
245 * @param {tcuTexture.PixelBufferAccess} depthBuffer
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]);
259 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
260 * @param {rrRenderState.StencilState} stencilState
261 * @param {number} numStencilBits
262 * @param {tcuTexture.PixelBufferAccess} stencilBuffer
264 rrFragmentOperations.executeStencilDpFailAndPass = function(inputFragments, stencilState, numStencilBits, stencilBuffer) {
265 var clampedStencilRef = deMath.clamp(stencilState.ref, 0, (1 << numStencilBits) - 1);
268 * @param {function(boolean):boolean} condition
269 * @param {function(number,number):number} expression
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]);
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);
297 var passed = function(depthPassed) { return depthPassed;};
298 var failed = function(depthPassed) { return !depthPassed;};
300 switch_dpfail_or_dppass('dpFail', failed);
301 switch_dpfail_or_dppass('dpPass', passed);
305 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
306 * @param {Array<number>} blendColor
307 * @param {rrRenderState.BlendState} blendRGBState
309 rrFragmentOperations.executeBlendFactorComputeRGB = function(inputFragments, blendColor, blendRGBState) {
311 * @param {string} factor_name
312 * @param {function(Array<number>, Array<number>, Array<number>):Array<number>} expression
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);
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);
371 switch_src_or_dst_factor_rgb('srcFunc', 'blendSrcFactorRGB');
372 switch_src_or_dst_factor_rgb('dstFunc', 'blendDstFactorRGB');
377 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
378 * @param {Array<number>} blendColor
379 * @param {rrRenderState.BlendState} blendAState
381 rrFragmentOperations.executeBlendFactorComputeA = function(inputFragments, blendColor, blendAState) {
383 * @param {string} factor_name
384 * @param {function(Array<number>, Array<number>, Array<number>):number} expression
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);
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);
443 swictch_src_or_dst_factor_a('srcFunc', 'blendSrcFactorA');
444 swictch_src_or_dst_factor_a('dstFunc', 'blendDstFactorA');
448 * @param {Array<rrFragmentOperations.Fragment>} inputFragments Fragments to write
449 * @param {rrRenderState.BlendState} blendRGBState
450 * @param {rrRenderState.BlendState} blendAState
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);
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);
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);
496 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
497 * @param {boolean} isSRGB
498 * @param {tcuTexture.PixelBufferAccess} colorBuffer
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);
509 colorBuffer.setPixel(combinedColor, 0, frag.pixelCoord[0], frag.pixelCoord[1]);
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
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;
530 if (isSRGB)
531 newColor = tcuTextureUtil.linearToSRGB(newColor);
533 newColor = deMath.add(deMath.multiply(colorMaskFactor, newColor), deMath.multiply(colorMaskNegationFactor, originalColor));
535 colorBuffer.setPixel(newColor, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
541 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
542 * @param {Array<boolean>} colorMask
543 * @param {tcuTexture.PixelBufferAccess} colorBuffer
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);
553 colorBuffer.setPixelInt(newValue, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
559 * @param {Array<rrFragmentOperations.Fragment>} inputFragments
560 * @param {Array<boolean>} colorMask
561 * @param {tcuTexture.PixelBufferAccess} colorBuffer
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);
571 colorBuffer.setPixelInt(newValue, fragSampleNdx, frag.pixelCoord[0], frag.pixelCoord[1]);
577 * @constructor
579 rrFragmentOperations.FragmentProcessor = function() {
580 /* TODO: implement */