blob: ca38074e7d1fa3a7e87994acb03d3009eeaf0379 [file] [log] [blame]
John Bauman89401822014-05-06 15:04:28 -04001// SwiftShader Software Renderer
2//
John Bauman66b8ab22014-05-06 15:57:45 -04003// Copyright(c) 2005-2013 TransGaming Inc.
John Bauman89401822014-05-06 15:04:28 -04004//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "PixelRoutine.hpp"
13
14#include "Renderer.hpp"
John Bauman89401822014-05-06 15:04:28 -040015#include "QuadRasterizer.hpp"
16#include "Surface.hpp"
17#include "Primitive.hpp"
18#include "CPUID.hpp"
19#include "SamplerCore.hpp"
20#include "Constants.hpp"
21#include "Debug.hpp"
22
John Bauman89401822014-05-06 15:04:28 -040023namespace sw
24{
25 extern bool complementaryDepthBuffer;
26 extern bool postBlendSRGB;
27 extern bool exactColorRounding;
Alexis Hetuf2a8c372015-07-13 11:08:41 -040028 extern bool forceClearRegisters;
John Bauman89401822014-05-06 15:04:28 -040029
Nicolas Capens4f172c72016-01-13 08:34:30 -050030 PixelRoutine::PixelRoutine(const PixelProcessor::State &state, const PixelShader *shader) : QuadRasterizer(state, shader), v(shader && shader->dynamicallyIndexedInput)
John Bauman89401822014-05-06 15:04:28 -040031 {
Alexis Hetuf2a8c372015-07-13 11:08:41 -040032 if(!shader || shader->getVersion() < 0x0200 || forceClearRegisters)
John Bauman89401822014-05-06 15:04:28 -040033 {
Alexis Hetuf2a8c372015-07-13 11:08:41 -040034 for(int i = 0; i < 10; i++)
35 {
Alexis Hetu3e1fd3a2015-08-11 10:15:34 -040036 v[i].x = Float4(0.0f);
37 v[i].y = Float4(0.0f);
38 v[i].z = Float4(0.0f);
39 v[i].w = Float4(0.0f);
Alexis Hetuf2a8c372015-07-13 11:08:41 -040040 }
John Bauman89401822014-05-06 15:04:28 -040041 }
42 }
43
44 PixelRoutine::~PixelRoutine()
45 {
Alexis Hetu0b65c5e2015-03-31 11:48:57 -040046 for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++)
John Bauman89401822014-05-06 15:04:28 -040047 {
48 delete sampler[i];
49 }
50 }
51
Nicolas Capens4f172c72016-01-13 08:34:30 -050052 void PixelRoutine::quad(Pointer<Byte> cBuffer[RENDERTARGETS], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x, Int &y)
John Bauman89401822014-05-06 15:04:28 -040053 {
54 #if PERF_PROFILE
55 Long pipeTime = Ticks();
56 #endif
57
Alexis Hetu0b65c5e2015-03-31 11:48:57 -040058 for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++)
John Bauman89401822014-05-06 15:04:28 -040059 {
Nicolas Capens4f172c72016-01-13 08:34:30 -050060 sampler[i] = new SamplerCore(constants, state.sampler[i]);
John Bauman89401822014-05-06 15:04:28 -040061 }
62
63 const bool earlyDepthTest = !state.depthOverride && !state.alphaTestActive();
John Bauman89401822014-05-06 15:04:28 -040064
65 Int zMask[4]; // Depth mask
66 Int sMask[4]; // Stencil mask
67
68 for(unsigned int q = 0; q < state.multiSample; q++)
69 {
70 zMask[q] = cMask[q];
71 sMask[q] = cMask[q];
72 }
73
74 for(unsigned int q = 0; q < state.multiSample; q++)
75 {
Nicolas Capens4f172c72016-01-13 08:34:30 -050076 stencilTest(sBuffer, q, x, sMask[q], cMask[q]);
John Bauman89401822014-05-06 15:04:28 -040077 }
78
79 Float4 f;
John Bauman89401822014-05-06 15:04:28 -040080 Float4 rhwCentroid;
81
Nicolas Capens4f172c72016-01-13 08:34:30 -050082 Float4 xxxx = Float4(Float(x)) + *Pointer<Float4>(primitive + OFFSET(Primitive,xQuad), 16);
John Bauman89401822014-05-06 15:04:28 -040083
John Bauman19bac1e2014-05-06 15:23:49 -040084 if(interpolateZ())
John Bauman89401822014-05-06 15:04:28 -040085 {
86 for(unsigned int q = 0; q < state.multiSample; q++)
87 {
88 Float4 x = xxxx;
Nicolas Capens4f172c72016-01-13 08:34:30 -050089
John Bauman89401822014-05-06 15:04:28 -040090 if(state.multiSample > 1)
91 {
Nicolas Capens4f172c72016-01-13 08:34:30 -050092 x -= *Pointer<Float4>(constants + OFFSET(Constants,X) + q * sizeof(float4));
John Bauman89401822014-05-06 15:04:28 -040093 }
94
Nicolas Capens4f172c72016-01-13 08:34:30 -050095 z[q] = interpolate(x, Dz[q], z[q], primitive + OFFSET(Primitive,z), false, false);
John Bauman89401822014-05-06 15:04:28 -040096 }
97 }
98
99 Bool depthPass = false;
100
101 if(earlyDepthTest)
102 {
103 for(unsigned int q = 0; q < state.multiSample; q++)
104 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500105 depthPass = depthPass || depthTest(zBuffer, q, x, z[q], sMask[q], zMask[q], cMask[q]);
John Bauman89401822014-05-06 15:04:28 -0400106 }
107 }
108
109 If(depthPass || Bool(!earlyDepthTest))
110 {
111 #if PERF_PROFILE
112 Long interpTime = Ticks();
113 #endif
114
Nicolas Capens4f172c72016-01-13 08:34:30 -0500115 Float4 yyyy = Float4(Float(y)) + *Pointer<Float4>(primitive + OFFSET(Primitive,yQuad), 16);
Nicolas Capenscbefe532014-10-16 00:16:01 -0400116
John Bauman89401822014-05-06 15:04:28 -0400117 // Centroid locations
118 Float4 XXXX = Float4(0.0f);
119 Float4 YYYY = Float4(0.0f);
120
121 if(state.centroid)
122 {
123 Float4 WWWW(1.0e-9f);
124
125 for(unsigned int q = 0; q < state.multiSample; q++)
126 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500127 XXXX += *Pointer<Float4>(constants + OFFSET(Constants,sampleX[q]) + 16 * cMask[q]);
128 YYYY += *Pointer<Float4>(constants + OFFSET(Constants,sampleY[q]) + 16 * cMask[q]);
129 WWWW += *Pointer<Float4>(constants + OFFSET(Constants,weight) + 16 * cMask[q]);
John Bauman89401822014-05-06 15:04:28 -0400130 }
131
132 WWWW = Rcp_pp(WWWW);
133 XXXX *= WWWW;
134 YYYY *= WWWW;
135
136 XXXX += xxxx;
137 YYYY += yyyy;
138 }
139
John Bauman19bac1e2014-05-06 15:23:49 -0400140 if(interpolateW())
John Bauman89401822014-05-06 15:04:28 -0400141 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500142 w = interpolate(xxxx, Dw, rhw, primitive + OFFSET(Primitive,w), false, false);
Nicolas Capens05b3d662016-02-25 23:58:33 -0500143 rhw = reciprocal(w, false, false, true);
John Bauman89401822014-05-06 15:04:28 -0400144
145 if(state.centroid)
146 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500147 rhwCentroid = reciprocal(interpolateCentroid(XXXX, YYYY, rhwCentroid, primitive + OFFSET(Primitive,w), false, false));
John Bauman89401822014-05-06 15:04:28 -0400148 }
149 }
150
151 for(int interpolant = 0; interpolant < 10; interpolant++)
152 {
153 for(int component = 0; component < 4; component++)
154 {
John Bauman89401822014-05-06 15:04:28 -0400155 if(state.interpolant[interpolant].component & (1 << component))
156 {
157 if(!state.interpolant[interpolant].centroid)
158 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500159 v[interpolant][component] = interpolate(xxxx, Dv[interpolant][component], rhw, primitive + OFFSET(Primitive, V[interpolant][component]), (state.interpolant[interpolant].flat & (1 << component)) != 0, state.perspective);
John Bauman89401822014-05-06 15:04:28 -0400160 }
161 else
162 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500163 v[interpolant][component] = interpolateCentroid(XXXX, YYYY, rhwCentroid, primitive + OFFSET(Primitive, V[interpolant][component]), (state.interpolant[interpolant].flat & (1 << component)) != 0, state.perspective);
John Bauman89401822014-05-06 15:04:28 -0400164 }
165 }
166 }
167
168 Float4 rcp;
169
170 switch(state.interpolant[interpolant].project)
171 {
172 case 0:
173 break;
174 case 1:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500175 rcp = reciprocal(v[interpolant].y);
176 v[interpolant].x = v[interpolant].x * rcp;
John Bauman89401822014-05-06 15:04:28 -0400177 break;
178 case 2:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500179 rcp = reciprocal(v[interpolant].z);
180 v[interpolant].x = v[interpolant].x * rcp;
181 v[interpolant].y = v[interpolant].y * rcp;
John Bauman89401822014-05-06 15:04:28 -0400182 break;
183 case 3:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500184 rcp = reciprocal(v[interpolant].w);
185 v[interpolant].x = v[interpolant].x * rcp;
186 v[interpolant].y = v[interpolant].y * rcp;
187 v[interpolant].z = v[interpolant].z * rcp;
John Bauman89401822014-05-06 15:04:28 -0400188 break;
189 }
190 }
191
192 if(state.fog.component)
193 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500194 f = interpolate(xxxx, Df, rhw, primitive + OFFSET(Primitive,f), state.fog.flat & 0x01, state.perspective);
John Bauman89401822014-05-06 15:04:28 -0400195 }
196
Nicolas Capens4f172c72016-01-13 08:34:30 -0500197 setBuiltins(x, y, z, w);
John Bauman89401822014-05-06 15:04:28 -0400198
199 #if PERF_PROFILE
Nicolas Capens4f172c72016-01-13 08:34:30 -0500200 cycles[PERF_INTERP] += Ticks() - interpTime;
John Bauman89401822014-05-06 15:04:28 -0400201 #endif
202
203 Bool alphaPass = true;
204
205 if(colorUsed())
206 {
207 #if PERF_PROFILE
208 Long shaderTime = Ticks();
209 #endif
210
Nicolas Capens4f172c72016-01-13 08:34:30 -0500211 applyShader(cMask);
John Bauman89401822014-05-06 15:04:28 -0400212
213 #if PERF_PROFILE
Nicolas Capens4f172c72016-01-13 08:34:30 -0500214 cycles[PERF_SHADER] += Ticks() - shaderTime;
John Bauman89401822014-05-06 15:04:28 -0400215 #endif
216
Nicolas Capens4f172c72016-01-13 08:34:30 -0500217 alphaPass = alphaTest(cMask);
John Bauman89401822014-05-06 15:04:28 -0400218
John Bauman19bac1e2014-05-06 15:23:49 -0400219 if((shader && shader->containsKill()) || state.alphaTestActive())
John Bauman89401822014-05-06 15:04:28 -0400220 {
221 for(unsigned int q = 0; q < state.multiSample; q++)
222 {
223 zMask[q] &= cMask[q];
224 sMask[q] &= cMask[q];
225 }
226 }
227 }
228
229 If(alphaPass)
230 {
231 if(!earlyDepthTest)
232 {
233 for(unsigned int q = 0; q < state.multiSample; q++)
234 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500235 depthPass = depthPass || depthTest(zBuffer, q, x, z[q], sMask[q], zMask[q], cMask[q]);
John Bauman89401822014-05-06 15:04:28 -0400236 }
237 }
238
239 #if PERF_PROFILE
240 Long ropTime = Ticks();
241 #endif
242
243 If(depthPass || Bool(earlyDepthTest))
244 {
245 for(unsigned int q = 0; q < state.multiSample; q++)
246 {
247 if(state.multiSampleMask & (1 << q))
248 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500249 writeDepth(zBuffer, q, x, z[q], zMask[q]);
John Bauman89401822014-05-06 15:04:28 -0400250
251 if(state.occlusionEnabled)
252 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500253 occlusion += *Pointer<UInt>(constants + OFFSET(Constants,occlusionCount) + 4 * (zMask[q] & sMask[q]));
John Bauman89401822014-05-06 15:04:28 -0400254 }
255 }
256 }
257
258 if(colorUsed())
259 {
260 #if PERF_PROFILE
John Bauman66b8ab22014-05-06 15:57:45 -0400261 AddAtomic(Pointer<Long>(&profiler.ropOperations), 4);
John Bauman89401822014-05-06 15:04:28 -0400262 #endif
263
Nicolas Capens4f172c72016-01-13 08:34:30 -0500264 rasterOperation(f, cBuffer, x, sMask, zMask, cMask);
John Bauman89401822014-05-06 15:04:28 -0400265 }
266 }
267
268 #if PERF_PROFILE
Nicolas Capens4f172c72016-01-13 08:34:30 -0500269 cycles[PERF_ROP] += Ticks() - ropTime;
John Bauman89401822014-05-06 15:04:28 -0400270 #endif
271 }
272 }
273
274 for(unsigned int q = 0; q < state.multiSample; q++)
275 {
276 if(state.multiSampleMask & (1 << q))
277 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500278 writeStencil(sBuffer, q, x, sMask[q], zMask[q], cMask[q]);
John Bauman89401822014-05-06 15:04:28 -0400279 }
280 }
281
282 #if PERF_PROFILE
Nicolas Capens4f172c72016-01-13 08:34:30 -0500283 cycles[PERF_PIPE] += Ticks() - pipeTime;
John Bauman89401822014-05-06 15:04:28 -0400284 #endif
285 }
286
John Bauman89401822014-05-06 15:04:28 -0400287 Float4 PixelRoutine::interpolateCentroid(Float4 &x, Float4 &y, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective)
288 {
289 Float4 interpolant = *Pointer<Float4>(planeEquation + OFFSET(PlaneEquation,C), 16);
290
291 if(!flat)
292 {
293 interpolant += x * *Pointer<Float4>(planeEquation + OFFSET(PlaneEquation,A), 16) +
294 y * *Pointer<Float4>(planeEquation + OFFSET(PlaneEquation,B), 16);
295
296 if(perspective)
297 {
298 interpolant *= rhw;
299 }
300 }
301
302 return interpolant;
303 }
304
Nicolas Capens4f172c72016-01-13 08:34:30 -0500305 void PixelRoutine::stencilTest(Pointer<Byte> &sBuffer, int q, Int &x, Int &sMask, Int &cMask)
John Bauman89401822014-05-06 15:04:28 -0400306 {
307 if(!state.stencilActive)
308 {
309 return;
310 }
311
312 // (StencilRef & StencilMask) CompFunc (StencilBufferValue & StencilMask)
313
314 Pointer<Byte> buffer = sBuffer + 2 * x;
315
316 if(q > 0)
317 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500318 buffer += q * *Pointer<Int>(data + OFFSET(DrawData,stencilSliceB));
John Bauman89401822014-05-06 15:04:28 -0400319 }
320
321 Byte8 value = As<Byte8>(Long1(*Pointer<UInt>(buffer)));
322 Byte8 valueCCW = value;
323
324 if(!state.noStencilMask)
325 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500326 value &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[0].testMaskQ));
John Bauman89401822014-05-06 15:04:28 -0400327 }
328
Nicolas Capens4f172c72016-01-13 08:34:30 -0500329 stencilTest(value, state.stencilCompareMode, false);
John Bauman89401822014-05-06 15:04:28 -0400330
331 if(state.twoSidedStencil)
332 {
333 if(!state.noStencilMaskCCW)
334 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500335 valueCCW &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].testMaskQ));
John Bauman89401822014-05-06 15:04:28 -0400336 }
337
Nicolas Capens4f172c72016-01-13 08:34:30 -0500338 stencilTest(valueCCW, state.stencilCompareModeCCW, true);
John Bauman89401822014-05-06 15:04:28 -0400339
Nicolas Capens4f172c72016-01-13 08:34:30 -0500340 value &= *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask));
341 valueCCW &= *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask));
John Bauman89401822014-05-06 15:04:28 -0400342 value |= valueCCW;
343 }
344
345 sMask = SignMask(value) & cMask;
346 }
347
Nicolas Capens4f172c72016-01-13 08:34:30 -0500348 void PixelRoutine::stencilTest(Byte8 &value, StencilCompareMode stencilCompareMode, bool CCW)
John Bauman89401822014-05-06 15:04:28 -0400349 {
350 Byte8 equal;
351
352 switch(stencilCompareMode)
353 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400354 case STENCIL_ALWAYS:
John Bauman89401822014-05-06 15:04:28 -0400355 value = Byte8(0xFFFFFFFFFFFFFFFF);
356 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400357 case STENCIL_NEVER:
John Bauman89401822014-05-06 15:04:28 -0400358 value = Byte8(0x0000000000000000);
359 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400360 case STENCIL_LESS: // a < b ~ b > a
John Bauman89401822014-05-06 15:04:28 -0400361 value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
Nicolas Capens4f172c72016-01-13 08:34:30 -0500362 value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ)));
John Bauman89401822014-05-06 15:04:28 -0400363 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400364 case STENCIL_EQUAL:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500365 value = CmpEQ(value, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedQ)));
John Bauman89401822014-05-06 15:04:28 -0400366 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400367 case STENCIL_NOTEQUAL: // a != b ~ !(a == b)
Nicolas Capens4f172c72016-01-13 08:34:30 -0500368 value = CmpEQ(value, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedQ)));
John Bauman89401822014-05-06 15:04:28 -0400369 value ^= Byte8(0xFFFFFFFFFFFFFFFF);
370 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400371 case STENCIL_LESSEQUAL: // a <= b ~ (b > a) || (a == b)
John Bauman89401822014-05-06 15:04:28 -0400372 equal = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500373 equal = CmpEQ(equal, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedQ)));
John Bauman89401822014-05-06 15:04:28 -0400374 value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
Nicolas Capens4f172c72016-01-13 08:34:30 -0500375 value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ)));
John Bauman89401822014-05-06 15:04:28 -0400376 value |= equal;
377 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400378 case STENCIL_GREATER: // a > b
Nicolas Capens4f172c72016-01-13 08:34:30 -0500379 equal = *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ));
John Bauman89401822014-05-06 15:04:28 -0400380 value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
381 equal = CmpGT(As<SByte8>(equal), As<SByte8>(value));
382 value = equal;
383 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400384 case STENCIL_GREATEREQUAL: // a >= b ~ !(a < b) ~ !(b > a)
John Bauman89401822014-05-06 15:04:28 -0400385 value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
Nicolas Capens4f172c72016-01-13 08:34:30 -0500386 value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ)));
John Bauman89401822014-05-06 15:04:28 -0400387 value ^= Byte8(0xFFFFFFFFFFFFFFFF);
388 break;
389 default:
390 ASSERT(false);
391 }
392 }
393
Nicolas Capens4f172c72016-01-13 08:34:30 -0500394 Bool PixelRoutine::depthTest(Pointer<Byte> &zBuffer, int q, Int &x, Float4 &z, Int &sMask, Int &zMask, Int &cMask)
John Bauman89401822014-05-06 15:04:28 -0400395 {
396 if(!state.depthTestActive)
397 {
398 return true;
399 }
400
401 Float4 Z = z;
402
John Bauman19bac1e2014-05-06 15:23:49 -0400403 if(shader && shader->depthOverride())
John Bauman89401822014-05-06 15:04:28 -0400404 {
405 if(complementaryDepthBuffer)
406 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500407 Z = Float4(1.0f) - oDepth;
John Bauman89401822014-05-06 15:04:28 -0400408 }
409 else
410 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500411 Z = oDepth;
John Bauman89401822014-05-06 15:04:28 -0400412 }
413 }
414
415 Pointer<Byte> buffer;
416 Int pitch;
417
418 if(!state.quadLayoutDepthBuffer)
419 {
420 buffer = zBuffer + 4 * x;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500421 pitch = *Pointer<Int>(data + OFFSET(DrawData,depthPitchB));
John Bauman89401822014-05-06 15:04:28 -0400422 }
423 else
424 {
425 buffer = zBuffer + 8 * x;
426 }
427
428 if(q > 0)
429 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500430 buffer += q * *Pointer<Int>(data + OFFSET(DrawData,depthSliceB));
John Bauman89401822014-05-06 15:04:28 -0400431 }
432
433 Float4 zValue;
434
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400435 if(state.depthCompareMode != DEPTH_NEVER || (state.depthCompareMode != DEPTH_ALWAYS && !state.depthWriteEnable))
John Bauman89401822014-05-06 15:04:28 -0400436 {
437 if(!state.quadLayoutDepthBuffer)
438 {
439 // FIXME: Properly optimizes?
440 zValue.xy = *Pointer<Float4>(buffer);
441 zValue.zw = *Pointer<Float4>(buffer + pitch - 8);
442 }
443 else
444 {
445 zValue = *Pointer<Float4>(buffer, 16);
446 }
447 }
448
449 Int4 zTest;
450
451 switch(state.depthCompareMode)
452 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400453 case DEPTH_ALWAYS:
John Bauman89401822014-05-06 15:04:28 -0400454 // Optimized
455 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400456 case DEPTH_NEVER:
John Bauman89401822014-05-06 15:04:28 -0400457 // Optimized
458 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400459 case DEPTH_EQUAL:
John Bauman89401822014-05-06 15:04:28 -0400460 zTest = CmpEQ(zValue, Z);
461 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400462 case DEPTH_NOTEQUAL:
John Bauman89401822014-05-06 15:04:28 -0400463 zTest = CmpNEQ(zValue, Z);
464 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400465 case DEPTH_LESS:
John Bauman89401822014-05-06 15:04:28 -0400466 if(complementaryDepthBuffer)
467 {
468 zTest = CmpLT(zValue, Z);
469 }
470 else
471 {
472 zTest = CmpNLE(zValue, Z);
473 }
474 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400475 case DEPTH_GREATEREQUAL:
John Bauman89401822014-05-06 15:04:28 -0400476 if(complementaryDepthBuffer)
477 {
478 zTest = CmpNLT(zValue, Z);
479 }
480 else
481 {
482 zTest = CmpLE(zValue, Z);
483 }
484 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400485 case DEPTH_LESSEQUAL:
John Bauman89401822014-05-06 15:04:28 -0400486 if(complementaryDepthBuffer)
487 {
488 zTest = CmpLE(zValue, Z);
489 }
490 else
491 {
492 zTest = CmpNLT(zValue, Z);
493 }
494 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400495 case DEPTH_GREATER:
John Bauman89401822014-05-06 15:04:28 -0400496 if(complementaryDepthBuffer)
497 {
498 zTest = CmpNLE(zValue, Z);
499 }
500 else
501 {
502 zTest = CmpLT(zValue, Z);
503 }
504 break;
505 default:
506 ASSERT(false);
507 }
508
509 switch(state.depthCompareMode)
510 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400511 case DEPTH_ALWAYS:
John Bauman89401822014-05-06 15:04:28 -0400512 zMask = cMask;
513 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400514 case DEPTH_NEVER:
John Bauman89401822014-05-06 15:04:28 -0400515 zMask = 0x0;
516 break;
517 default:
518 zMask = SignMask(zTest) & cMask;
519 break;
520 }
Nicolas Capens05b3d662016-02-25 23:58:33 -0500521
John Bauman89401822014-05-06 15:04:28 -0400522 if(state.stencilActive)
523 {
524 zMask &= sMask;
525 }
526
527 return zMask != 0;
528 }
529
Nicolas Capens4f172c72016-01-13 08:34:30 -0500530 void PixelRoutine::alphaTest(Int &aMask, Short4 &alpha)
John Bauman89401822014-05-06 15:04:28 -0400531 {
532 Short4 cmp;
533 Short4 equal;
534
535 switch(state.alphaCompareMode)
536 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400537 case ALPHA_ALWAYS:
John Bauman89401822014-05-06 15:04:28 -0400538 aMask = 0xF;
539 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400540 case ALPHA_NEVER:
John Bauman89401822014-05-06 15:04:28 -0400541 aMask = 0x0;
542 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400543 case ALPHA_EQUAL:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500544 cmp = CmpEQ(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
John Bauman89401822014-05-06 15:04:28 -0400545 aMask = SignMask(Pack(cmp, Short4(0x0000, 0x0000, 0x0000, 0x0000)));
546 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400547 case ALPHA_NOTEQUAL: // a != b ~ !(a == b)
Nicolas Capens4f172c72016-01-13 08:34:30 -0500548 cmp = CmpEQ(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4))) ^ Short4((short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF); // FIXME
John Bauman89401822014-05-06 15:04:28 -0400549 aMask = SignMask(Pack(cmp, Short4(0x0000, 0x0000, 0x0000, 0x0000)));
550 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400551 case ALPHA_LESS: // a < b ~ b > a
Nicolas Capens4f172c72016-01-13 08:34:30 -0500552 cmp = CmpGT(*Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)), alpha);
John Bauman89401822014-05-06 15:04:28 -0400553 aMask = SignMask(Pack(cmp, Short4(0x0000, 0x0000, 0x0000, 0x0000)));
554 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400555 case ALPHA_GREATEREQUAL: // a >= b ~ (a > b) || (a == b) ~ !(b > a) // TODO: Approximate
Nicolas Capens4f172c72016-01-13 08:34:30 -0500556 equal = CmpEQ(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
557 cmp = CmpGT(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
John Bauman89401822014-05-06 15:04:28 -0400558 cmp |= equal;
559 aMask = SignMask(Pack(cmp, Short4(0x0000, 0x0000, 0x0000, 0x0000)));
560 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400561 case ALPHA_LESSEQUAL: // a <= b ~ !(a > b)
Nicolas Capens4f172c72016-01-13 08:34:30 -0500562 cmp = CmpGT(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4))) ^ Short4((short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF); // FIXME
John Bauman89401822014-05-06 15:04:28 -0400563 aMask = SignMask(Pack(cmp, Short4(0x0000, 0x0000, 0x0000, 0x0000)));
564 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400565 case ALPHA_GREATER: // a > b
Nicolas Capens4f172c72016-01-13 08:34:30 -0500566 cmp = CmpGT(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
John Bauman89401822014-05-06 15:04:28 -0400567 aMask = SignMask(Pack(cmp, Short4(0x0000, 0x0000, 0x0000, 0x0000)));
568 break;
569 default:
570 ASSERT(false);
571 }
572 }
573
Nicolas Capens4f172c72016-01-13 08:34:30 -0500574 void PixelRoutine::alphaToCoverage(Int cMask[4], Float4 &alpha)
John Bauman89401822014-05-06 15:04:28 -0400575 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500576 Int4 coverage0 = CmpNLT(alpha, *Pointer<Float4>(data + OFFSET(DrawData,a2c0)));
577 Int4 coverage1 = CmpNLT(alpha, *Pointer<Float4>(data + OFFSET(DrawData,a2c1)));
578 Int4 coverage2 = CmpNLT(alpha, *Pointer<Float4>(data + OFFSET(DrawData,a2c2)));
579 Int4 coverage3 = CmpNLT(alpha, *Pointer<Float4>(data + OFFSET(DrawData,a2c3)));
John Bauman89401822014-05-06 15:04:28 -0400580
581 Int aMask0 = SignMask(coverage0);
582 Int aMask1 = SignMask(coverage1);
583 Int aMask2 = SignMask(coverage2);
584 Int aMask3 = SignMask(coverage3);
585
586 cMask[0] &= aMask0;
587 cMask[1] &= aMask1;
588 cMask[2] &= aMask2;
589 cMask[3] &= aMask3;
590 }
591
Nicolas Capens4f172c72016-01-13 08:34:30 -0500592 void PixelRoutine::fogBlend(Vector4f &c0, Float4 &fog)
John Bauman89401822014-05-06 15:04:28 -0400593 {
594 if(!state.fogActive)
595 {
596 return;
597 }
598
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400599 if(state.pixelFogMode != FOG_NONE)
John Bauman89401822014-05-06 15:04:28 -0400600 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500601 pixelFog(fog);
John Bauman89401822014-05-06 15:04:28 -0400602
John Bauman19bac1e2014-05-06 15:23:49 -0400603 fog = Min(fog, Float4(1.0f));
604 fog = Max(fog, Float4(0.0f));
John Bauman89401822014-05-06 15:04:28 -0400605 }
606
Nicolas Capens4f172c72016-01-13 08:34:30 -0500607 c0.x -= *Pointer<Float4>(data + OFFSET(DrawData,fog.colorF[0]));
608 c0.y -= *Pointer<Float4>(data + OFFSET(DrawData,fog.colorF[1]));
609 c0.z -= *Pointer<Float4>(data + OFFSET(DrawData,fog.colorF[2]));
John Bauman89401822014-05-06 15:04:28 -0400610
John Bauman19bac1e2014-05-06 15:23:49 -0400611 c0.x *= fog;
612 c0.y *= fog;
613 c0.z *= fog;
John Bauman89401822014-05-06 15:04:28 -0400614
Nicolas Capens4f172c72016-01-13 08:34:30 -0500615 c0.x += *Pointer<Float4>(data + OFFSET(DrawData,fog.colorF[0]));
616 c0.y += *Pointer<Float4>(data + OFFSET(DrawData,fog.colorF[1]));
617 c0.z += *Pointer<Float4>(data + OFFSET(DrawData,fog.colorF[2]));
John Bauman89401822014-05-06 15:04:28 -0400618 }
619
Nicolas Capens4f172c72016-01-13 08:34:30 -0500620 void PixelRoutine::pixelFog(Float4 &visibility)
John Bauman89401822014-05-06 15:04:28 -0400621 {
622 Float4 &zw = visibility;
623
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400624 if(state.pixelFogMode != FOG_NONE)
John Bauman89401822014-05-06 15:04:28 -0400625 {
626 if(state.wBasedFog)
627 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500628 zw = rhw;
John Bauman89401822014-05-06 15:04:28 -0400629 }
630 else
631 {
632 if(complementaryDepthBuffer)
633 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500634 zw = Float4(1.0f) - z[0];
John Bauman89401822014-05-06 15:04:28 -0400635 }
636 else
637 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500638 zw = z[0];
John Bauman89401822014-05-06 15:04:28 -0400639 }
640 }
641 }
642
643 switch(state.pixelFogMode)
644 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400645 case FOG_NONE:
John Bauman89401822014-05-06 15:04:28 -0400646 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400647 case FOG_LINEAR:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500648 zw *= *Pointer<Float4>(data + OFFSET(DrawData,fog.scale));
649 zw += *Pointer<Float4>(data + OFFSET(DrawData,fog.offset));
John Bauman89401822014-05-06 15:04:28 -0400650 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400651 case FOG_EXP:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500652 zw *= *Pointer<Float4>(data + OFFSET(DrawData,fog.densityE));
John Bauman19bac1e2014-05-06 15:23:49 -0400653 zw = exponential2(zw, true);
John Bauman89401822014-05-06 15:04:28 -0400654 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400655 case FOG_EXP2:
John Bauman89401822014-05-06 15:04:28 -0400656 zw *= zw;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500657 zw *= *Pointer<Float4>(data + OFFSET(DrawData,fog.density2E));
John Bauman19bac1e2014-05-06 15:23:49 -0400658 zw = exponential2(zw, true);
John Bauman89401822014-05-06 15:04:28 -0400659 break;
660 default:
661 ASSERT(false);
662 }
663 }
664
Nicolas Capens4f172c72016-01-13 08:34:30 -0500665 void PixelRoutine::writeDepth(Pointer<Byte> &zBuffer, int q, Int &x, Float4 &z, Int &zMask)
John Bauman89401822014-05-06 15:04:28 -0400666 {
667 if(!state.depthWriteEnable)
668 {
669 return;
670 }
671
672 Float4 Z = z;
673
John Bauman19bac1e2014-05-06 15:23:49 -0400674 if(shader && shader->depthOverride())
John Bauman89401822014-05-06 15:04:28 -0400675 {
676 if(complementaryDepthBuffer)
677 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500678 Z = Float4(1.0f) - oDepth;
John Bauman89401822014-05-06 15:04:28 -0400679 }
680 else
681 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500682 Z = oDepth;
John Bauman89401822014-05-06 15:04:28 -0400683 }
684 }
685
686 Pointer<Byte> buffer;
687 Int pitch;
688
689 if(!state.quadLayoutDepthBuffer)
Nicolas Capens05b3d662016-02-25 23:58:33 -0500690 {
John Bauman89401822014-05-06 15:04:28 -0400691 buffer = zBuffer + 4 * x;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500692 pitch = *Pointer<Int>(data + OFFSET(DrawData,depthPitchB));
John Bauman89401822014-05-06 15:04:28 -0400693 }
694 else
Nicolas Capens05b3d662016-02-25 23:58:33 -0500695 {
John Bauman89401822014-05-06 15:04:28 -0400696 buffer = zBuffer + 8 * x;
697 }
698
699 if(q > 0)
700 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500701 buffer += q * *Pointer<Int>(data + OFFSET(DrawData,depthSliceB));
John Bauman89401822014-05-06 15:04:28 -0400702 }
703
704 Float4 zValue;
705
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400706 if(state.depthCompareMode != DEPTH_NEVER || (state.depthCompareMode != DEPTH_ALWAYS && !state.depthWriteEnable))
John Bauman89401822014-05-06 15:04:28 -0400707 {
708 if(!state.quadLayoutDepthBuffer)
709 {
710 // FIXME: Properly optimizes?
711 zValue.xy = *Pointer<Float4>(buffer);
712 zValue.zw = *Pointer<Float4>(buffer + pitch - 8);
713 }
714 else
715 {
716 zValue = *Pointer<Float4>(buffer, 16);
717 }
718 }
719
Nicolas Capens4f172c72016-01-13 08:34:30 -0500720 Z = As<Float4>(As<Int4>(Z) & *Pointer<Int4>(constants + OFFSET(Constants,maskD4X) + zMask * 16, 16));
721 zValue = As<Float4>(As<Int4>(zValue) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD4X) + zMask * 16, 16));
John Bauman89401822014-05-06 15:04:28 -0400722 Z = As<Float4>(As<Int4>(Z) | As<Int4>(zValue));
723
724 if(!state.quadLayoutDepthBuffer)
725 {
726 // FIXME: Properly optimizes?
727 *Pointer<Float2>(buffer) = Float2(Z.xy);
728 *Pointer<Float2>(buffer + pitch) = Float2(Z.zw);
729 }
730 else
731 {
732 *Pointer<Float4>(buffer, 16) = Z;
733 }
734 }
735
Nicolas Capens4f172c72016-01-13 08:34:30 -0500736 void PixelRoutine::writeStencil(Pointer<Byte> &sBuffer, int q, Int &x, Int &sMask, Int &zMask, Int &cMask)
John Bauman89401822014-05-06 15:04:28 -0400737 {
738 if(!state.stencilActive)
739 {
740 return;
741 }
742
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400743 if(state.stencilPassOperation == OPERATION_KEEP && state.stencilZFailOperation == OPERATION_KEEP && state.stencilFailOperation == OPERATION_KEEP)
John Bauman89401822014-05-06 15:04:28 -0400744 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400745 if(!state.twoSidedStencil || (state.stencilPassOperationCCW == OPERATION_KEEP && state.stencilZFailOperationCCW == OPERATION_KEEP && state.stencilFailOperationCCW == OPERATION_KEEP))
John Bauman89401822014-05-06 15:04:28 -0400746 {
747 return;
748 }
749 }
750
751 if(state.stencilWriteMasked && (!state.twoSidedStencil || state.stencilWriteMaskedCCW))
752 {
753 return;
754 }
755
756 Pointer<Byte> buffer = sBuffer + 2 * x;
757
758 if(q > 0)
759 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500760 buffer += q * *Pointer<Int>(data + OFFSET(DrawData,stencilSliceB));
John Bauman89401822014-05-06 15:04:28 -0400761 }
762
763 Byte8 bufferValue = As<Byte8>(Long1(*Pointer<UInt>(buffer)));
Nicolas Capens05b3d662016-02-25 23:58:33 -0500764
John Bauman89401822014-05-06 15:04:28 -0400765 Byte8 newValue;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500766 stencilOperation(newValue, bufferValue, state.stencilPassOperation, state.stencilZFailOperation, state.stencilFailOperation, false, zMask, sMask);
John Bauman89401822014-05-06 15:04:28 -0400767
768 if(!state.noStencilWriteMask)
769 {
770 Byte8 maskedValue = bufferValue;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500771 newValue &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[0].writeMaskQ));
772 maskedValue &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[0].invWriteMaskQ));
John Bauman89401822014-05-06 15:04:28 -0400773 newValue |= maskedValue;
774 }
775
776 if(state.twoSidedStencil)
777 {
778 Byte8 newValueCCW;
779
Nicolas Capens4f172c72016-01-13 08:34:30 -0500780 stencilOperation(newValueCCW, bufferValue, state.stencilPassOperationCCW, state.stencilZFailOperationCCW, state.stencilFailOperationCCW, true, zMask, sMask);
John Bauman89401822014-05-06 15:04:28 -0400781
782 if(!state.noStencilWriteMaskCCW)
783 {
784 Byte8 maskedValue = bufferValue;
Nicolas Capens4f172c72016-01-13 08:34:30 -0500785 newValueCCW &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].writeMaskQ));
786 maskedValue &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].invWriteMaskQ));
John Bauman89401822014-05-06 15:04:28 -0400787 newValueCCW |= maskedValue;
788 }
789
Nicolas Capens4f172c72016-01-13 08:34:30 -0500790 newValue &= *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask));
791 newValueCCW &= *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask));
John Bauman89401822014-05-06 15:04:28 -0400792 newValue |= newValueCCW;
793 }
794
Nicolas Capens4f172c72016-01-13 08:34:30 -0500795 newValue &= *Pointer<Byte8>(constants + OFFSET(Constants,maskB4Q) + 8 * cMask);
796 bufferValue &= *Pointer<Byte8>(constants + OFFSET(Constants,invMaskB4Q) + 8 * cMask);
John Bauman89401822014-05-06 15:04:28 -0400797 newValue |= bufferValue;
798
799 *Pointer<UInt>(buffer) = UInt(As<Long>(newValue));
800 }
801
Nicolas Capens4f172c72016-01-13 08:34:30 -0500802 void PixelRoutine::stencilOperation(Byte8 &newValue, Byte8 &bufferValue, StencilOperation stencilPassOperation, StencilOperation stencilZFailOperation, StencilOperation stencilFailOperation, bool CCW, Int &zMask, Int &sMask)
John Bauman89401822014-05-06 15:04:28 -0400803 {
804 Byte8 &pass = newValue;
805 Byte8 fail;
806 Byte8 zFail;
807
Nicolas Capens4f172c72016-01-13 08:34:30 -0500808 stencilOperation(pass, bufferValue, stencilPassOperation, CCW);
John Bauman89401822014-05-06 15:04:28 -0400809
810 if(stencilZFailOperation != stencilPassOperation)
811 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500812 stencilOperation(zFail, bufferValue, stencilZFailOperation, CCW);
John Bauman89401822014-05-06 15:04:28 -0400813 }
814
815 if(stencilFailOperation != stencilPassOperation || stencilFailOperation != stencilZFailOperation)
816 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500817 stencilOperation(fail, bufferValue, stencilFailOperation, CCW);
John Bauman89401822014-05-06 15:04:28 -0400818 }
819
820 if(stencilFailOperation != stencilPassOperation || stencilFailOperation != stencilZFailOperation)
821 {
822 if(state.depthTestActive && stencilZFailOperation != stencilPassOperation) // zMask valid and values not the same
823 {
Nicolas Capens4f172c72016-01-13 08:34:30 -0500824 pass &= *Pointer<Byte8>(constants + OFFSET(Constants,maskB4Q) + 8 * zMask);
825 zFail &= *Pointer<Byte8>(constants + OFFSET(Constants,invMaskB4Q) + 8 * zMask);
John Bauman89401822014-05-06 15:04:28 -0400826 pass |= zFail;
827 }
828
Nicolas Capens4f172c72016-01-13 08:34:30 -0500829 pass &= *Pointer<Byte8>(constants + OFFSET(Constants,maskB4Q) + 8 * sMask);
830 fail &= *Pointer<Byte8>(constants + OFFSET(Constants,invMaskB4Q) + 8 * sMask);
John Bauman89401822014-05-06 15:04:28 -0400831 pass |= fail;
832 }
833 }
834
Nicolas Capens4f172c72016-01-13 08:34:30 -0500835 void PixelRoutine::stencilOperation(Byte8 &output, Byte8 &bufferValue, StencilOperation operation, bool CCW)
John Bauman89401822014-05-06 15:04:28 -0400836 {
837 switch(operation)
838 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400839 case OPERATION_KEEP:
John Bauman89401822014-05-06 15:04:28 -0400840 output = bufferValue;
841 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400842 case OPERATION_ZERO:
John Bauman89401822014-05-06 15:04:28 -0400843 output = Byte8(0x0000000000000000);
844 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400845 case OPERATION_REPLACE:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500846 output = *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceQ));
John Bauman89401822014-05-06 15:04:28 -0400847 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400848 case OPERATION_INCRSAT:
John Bauman89401822014-05-06 15:04:28 -0400849 output = AddSat(bufferValue, Byte8(1, 1, 1, 1, 1, 1, 1, 1));
850 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400851 case OPERATION_DECRSAT:
John Bauman89401822014-05-06 15:04:28 -0400852 output = SubSat(bufferValue, Byte8(1, 1, 1, 1, 1, 1, 1, 1));
853 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400854 case OPERATION_INVERT:
John Bauman89401822014-05-06 15:04:28 -0400855 output = bufferValue ^ Byte8(0xFFFFFFFFFFFFFFFF);
856 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400857 case OPERATION_INCR:
John Bauman89401822014-05-06 15:04:28 -0400858 output = bufferValue + Byte8(1, 1, 1, 1, 1, 1, 1, 1);
859 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400860 case OPERATION_DECR:
John Bauman89401822014-05-06 15:04:28 -0400861 output = bufferValue - Byte8(1, 1, 1, 1, 1, 1, 1, 1);
862 break;
863 default:
864 ASSERT(false);
865 }
866 }
867
Nicolas Capens4f172c72016-01-13 08:34:30 -0500868 void PixelRoutine::blendFactor(const Vector4s &blendFactor, const Vector4s &current, const Vector4s &pixel, BlendFactor blendFactorActive)
John Bauman89401822014-05-06 15:04:28 -0400869 {
870 switch(blendFactorActive)
871 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400872 case BLEND_ZERO:
John Bauman89401822014-05-06 15:04:28 -0400873 // Optimized
874 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400875 case BLEND_ONE:
John Bauman89401822014-05-06 15:04:28 -0400876 // Optimized
877 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400878 case BLEND_SOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -0400879 blendFactor.x = current.x;
880 blendFactor.y = current.y;
881 blendFactor.z = current.z;
John Bauman89401822014-05-06 15:04:28 -0400882 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400883 case BLEND_INVSOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -0400884 blendFactor.x = Short4(0xFFFFu) - current.x;
885 blendFactor.y = Short4(0xFFFFu) - current.y;
886 blendFactor.z = Short4(0xFFFFu) - current.z;
John Bauman89401822014-05-06 15:04:28 -0400887 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400888 case BLEND_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -0400889 blendFactor.x = pixel.x;
890 blendFactor.y = pixel.y;
891 blendFactor.z = pixel.z;
John Bauman89401822014-05-06 15:04:28 -0400892 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400893 case BLEND_INVDEST:
John Bauman19bac1e2014-05-06 15:23:49 -0400894 blendFactor.x = Short4(0xFFFFu) - pixel.x;
895 blendFactor.y = Short4(0xFFFFu) - pixel.y;
896 blendFactor.z = Short4(0xFFFFu) - pixel.z;
John Bauman89401822014-05-06 15:04:28 -0400897 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400898 case BLEND_SOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400899 blendFactor.x = current.w;
900 blendFactor.y = current.w;
901 blendFactor.z = current.w;
John Bauman89401822014-05-06 15:04:28 -0400902 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400903 case BLEND_INVSOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400904 blendFactor.x = Short4(0xFFFFu) - current.w;
905 blendFactor.y = Short4(0xFFFFu) - current.w;
906 blendFactor.z = Short4(0xFFFFu) - current.w;
John Bauman89401822014-05-06 15:04:28 -0400907 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400908 case BLEND_DESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400909 blendFactor.x = pixel.w;
910 blendFactor.y = pixel.w;
911 blendFactor.z = pixel.w;
John Bauman89401822014-05-06 15:04:28 -0400912 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400913 case BLEND_INVDESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400914 blendFactor.x = Short4(0xFFFFu) - pixel.w;
915 blendFactor.y = Short4(0xFFFFu) - pixel.w;
916 blendFactor.z = Short4(0xFFFFu) - pixel.w;
John Bauman89401822014-05-06 15:04:28 -0400917 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400918 case BLEND_SRCALPHASAT:
John Bauman19bac1e2014-05-06 15:23:49 -0400919 blendFactor.x = Short4(0xFFFFu) - pixel.w;
920 blendFactor.x = Min(As<UShort4>(blendFactor.x), As<UShort4>(current.w));
921 blendFactor.y = blendFactor.x;
922 blendFactor.z = blendFactor.x;
John Bauman89401822014-05-06 15:04:28 -0400923 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400924 case BLEND_CONSTANT:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500925 blendFactor.x = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[0]));
926 blendFactor.y = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[1]));
927 blendFactor.z = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[2]));
John Bauman89401822014-05-06 15:04:28 -0400928 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400929 case BLEND_INVCONSTANT:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500930 blendFactor.x = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[0]));
931 blendFactor.y = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[1]));
932 blendFactor.z = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[2]));
John Bauman89401822014-05-06 15:04:28 -0400933 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400934 case BLEND_CONSTANTALPHA:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500935 blendFactor.x = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[3]));
936 blendFactor.y = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[3]));
937 blendFactor.z = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[3]));
John Bauman89401822014-05-06 15:04:28 -0400938 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400939 case BLEND_INVCONSTANTALPHA:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500940 blendFactor.x = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[3]));
941 blendFactor.y = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[3]));
942 blendFactor.z = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[3]));
John Bauman89401822014-05-06 15:04:28 -0400943 break;
944 default:
945 ASSERT(false);
946 }
947 }
Nicolas Capens05b3d662016-02-25 23:58:33 -0500948
Nicolas Capens4f172c72016-01-13 08:34:30 -0500949 void PixelRoutine::blendFactorAlpha(const Vector4s &blendFactor, const Vector4s &current, const Vector4s &pixel, BlendFactor blendFactorAlphaActive)
John Bauman89401822014-05-06 15:04:28 -0400950 {
951 switch(blendFactorAlphaActive)
952 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400953 case BLEND_ZERO:
John Bauman89401822014-05-06 15:04:28 -0400954 // Optimized
955 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400956 case BLEND_ONE:
John Bauman89401822014-05-06 15:04:28 -0400957 // Optimized
958 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400959 case BLEND_SOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -0400960 blendFactor.w = current.w;
John Bauman89401822014-05-06 15:04:28 -0400961 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400962 case BLEND_INVSOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -0400963 blendFactor.w = Short4(0xFFFFu) - current.w;
John Bauman89401822014-05-06 15:04:28 -0400964 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400965 case BLEND_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -0400966 blendFactor.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -0400967 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400968 case BLEND_INVDEST:
John Bauman19bac1e2014-05-06 15:23:49 -0400969 blendFactor.w = Short4(0xFFFFu) - pixel.w;
John Bauman89401822014-05-06 15:04:28 -0400970 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400971 case BLEND_SOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400972 blendFactor.w = current.w;
John Bauman89401822014-05-06 15:04:28 -0400973 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400974 case BLEND_INVSOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400975 blendFactor.w = Short4(0xFFFFu) - current.w;
John Bauman89401822014-05-06 15:04:28 -0400976 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400977 case BLEND_DESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400978 blendFactor.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -0400979 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400980 case BLEND_INVDESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -0400981 blendFactor.w = Short4(0xFFFFu) - pixel.w;
John Bauman89401822014-05-06 15:04:28 -0400982 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400983 case BLEND_SRCALPHASAT:
John Bauman19bac1e2014-05-06 15:23:49 -0400984 blendFactor.w = Short4(0xFFFFu);
John Bauman89401822014-05-06 15:04:28 -0400985 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400986 case BLEND_CONSTANT:
987 case BLEND_CONSTANTALPHA:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500988 blendFactor.w = *Pointer<Short4>(data + OFFSET(DrawData,factor.blendConstant4W[3]));
John Bauman89401822014-05-06 15:04:28 -0400989 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400990 case BLEND_INVCONSTANT:
991 case BLEND_INVCONSTANTALPHA:
Nicolas Capens4f172c72016-01-13 08:34:30 -0500992 blendFactor.w = *Pointer<Short4>(data + OFFSET(DrawData,factor.invBlendConstant4W[3]));
John Bauman89401822014-05-06 15:04:28 -0400993 break;
994 default:
995 ASSERT(false);
996 }
997 }
998
Nicolas Capens4f172c72016-01-13 08:34:30 -0500999 void PixelRoutine::readPixel(int index, Pointer<Byte> &cBuffer, Int &x, Vector4s &pixel)
John Bauman89401822014-05-06 15:04:28 -04001000 {
John Bauman89401822014-05-06 15:04:28 -04001001 Short4 c01;
1002 Short4 c23;
Maxime Grégoired9762742015-07-08 16:43:48 -04001003 Pointer<Byte> buffer;
Nicolas Capensb40a2562016-01-05 00:08:45 -05001004 Pointer<Byte> buffer2;
John Bauman89401822014-05-06 15:04:28 -04001005
John Bauman89401822014-05-06 15:04:28 -04001006 switch(state.targetFormat[index])
1007 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001008 case FORMAT_R5G6B5:
1009 buffer = cBuffer + 2 * x;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001010 buffer2 = buffer + *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
Nicolas Capensb40a2562016-01-05 00:08:45 -05001011 c01 = As<Short4>(Int2(*Pointer<Int>(buffer), *Pointer<Int>(buffer2)));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001012
1013 pixel.x = c01 & Short4(0xF800u);
1014 pixel.y = (c01 & Short4(0x07E0u)) << 5;
1015 pixel.z = (c01 & Short4(0x001Fu)) << 11;
1016 pixel.w = Short4(0xFFFFu);
1017 break;
John Bauman89401822014-05-06 15:04:28 -04001018 case FORMAT_A8R8G8B8:
1019 buffer = cBuffer + 4 * x;
1020 c01 = *Pointer<Short4>(buffer);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001021 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04001022 c23 = *Pointer<Short4>(buffer);
John Bauman19bac1e2014-05-06 15:23:49 -04001023 pixel.z = c01;
1024 pixel.y = c01;
1025 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(c23));
1026 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(c23));
1027 pixel.x = pixel.z;
1028 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.y));
1029 pixel.x = UnpackHigh(As<Byte8>(pixel.x), As<Byte8>(pixel.y));
1030 pixel.y = pixel.z;
1031 pixel.w = pixel.x;
1032 pixel.x = UnpackLow(As<Byte8>(pixel.x), As<Byte8>(pixel.x));
1033 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(pixel.y));
1034 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.z));
1035 pixel.w = UnpackHigh(As<Byte8>(pixel.w), As<Byte8>(pixel.w));
John Bauman89401822014-05-06 15:04:28 -04001036 break;
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001037 case FORMAT_A8B8G8R8:
1038 buffer = cBuffer + 4 * x;
1039 c01 = *Pointer<Short4>(buffer);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001040 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001041 c23 = *Pointer<Short4>(buffer);
1042 pixel.z = c01;
1043 pixel.y = c01;
1044 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(c23));
1045 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(c23));
1046 pixel.x = pixel.z;
1047 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.y));
1048 pixel.x = UnpackHigh(As<Byte8>(pixel.x), As<Byte8>(pixel.y));
1049 pixel.y = pixel.z;
1050 pixel.w = pixel.x;
1051 pixel.x = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.z));
1052 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(pixel.y));
1053 pixel.z = UnpackLow(As<Byte8>(pixel.w), As<Byte8>(pixel.w));
1054 pixel.w = UnpackHigh(As<Byte8>(pixel.w), As<Byte8>(pixel.w));
1055 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001056 case FORMAT_A8:
1057 buffer = cBuffer + 1 * x;
1058 pixel.w = Insert(pixel.w, *Pointer<Short>(buffer), 0);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001059 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
John Bauman66b8ab22014-05-06 15:57:45 -04001060 pixel.w = Insert(pixel.w, *Pointer<Short>(buffer), 1);
1061 pixel.w = UnpackLow(As<Byte8>(pixel.w), As<Byte8>(pixel.w));
1062 pixel.x = Short4(0x0000);
1063 pixel.y = Short4(0x0000);
1064 pixel.z = Short4(0x0000);
1065 break;
John Bauman89401822014-05-06 15:04:28 -04001066 case FORMAT_X8R8G8B8:
1067 buffer = cBuffer + 4 * x;
1068 c01 = *Pointer<Short4>(buffer);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001069 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04001070 c23 = *Pointer<Short4>(buffer);
John Bauman19bac1e2014-05-06 15:23:49 -04001071 pixel.z = c01;
1072 pixel.y = c01;
1073 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(c23));
1074 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(c23));
1075 pixel.x = pixel.z;
1076 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.y));
1077 pixel.x = UnpackHigh(As<Byte8>(pixel.x), As<Byte8>(pixel.y));
1078 pixel.y = pixel.z;
1079 pixel.x = UnpackLow(As<Byte8>(pixel.x), As<Byte8>(pixel.x));
1080 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(pixel.y));
1081 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.z));
1082 pixel.w = Short4(0xFFFFu);
John Bauman89401822014-05-06 15:04:28 -04001083 break;
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001084 case FORMAT_X8B8G8R8:
1085 buffer = cBuffer + 4 * x;
1086 c01 = *Pointer<Short4>(buffer);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001087 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001088 c23 = *Pointer<Short4>(buffer);
1089 pixel.z = c01;
1090 pixel.y = c01;
1091 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(c23));
1092 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(c23));
1093 pixel.x = pixel.z;
1094 pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.y));
1095 pixel.x = UnpackHigh(As<Byte8>(pixel.x), As<Byte8>(pixel.y));
1096 pixel.y = pixel.z;
1097 pixel.w = pixel.x;
1098 pixel.x = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.z));
1099 pixel.y = UnpackHigh(As<Byte8>(pixel.y), As<Byte8>(pixel.y));
1100 pixel.z = UnpackLow(As<Byte8>(pixel.w), As<Byte8>(pixel.w));
1101 pixel.w = Short4(0xFFFFu);
1102 break;
John Bauman89401822014-05-06 15:04:28 -04001103 case FORMAT_A8G8R8B8Q:
1104 UNIMPLEMENTED();
Nicolas Capens64750b52015-09-22 10:11:00 -04001105 // pixel.z = UnpackLow(As<Byte8>(pixel.z), *Pointer<Byte8>(cBuffer + 8 * x + 0));
1106 // pixel.x = UnpackHigh(As<Byte8>(pixel.x), *Pointer<Byte8>(cBuffer + 8 * x + 0));
1107 // pixel.y = UnpackLow(As<Byte8>(pixel.y), *Pointer<Byte8>(cBuffer + 8 * x + 8));
1108 // pixel.w = UnpackHigh(As<Byte8>(pixel.w), *Pointer<Byte8>(cBuffer + 8 * x + 8));
John Bauman89401822014-05-06 15:04:28 -04001109 break;
1110 case FORMAT_X8G8R8B8Q:
1111 UNIMPLEMENTED();
Nicolas Capens64750b52015-09-22 10:11:00 -04001112 // pixel.z = UnpackLow(As<Byte8>(pixel.z), *Pointer<Byte8>(cBuffer + 8 * x + 0));
1113 // pixel.x = UnpackHigh(As<Byte8>(pixel.x), *Pointer<Byte8>(cBuffer + 8 * x + 0));
1114 // pixel.y = UnpackLow(As<Byte8>(pixel.y), *Pointer<Byte8>(cBuffer + 8 * x + 8));
1115 // pixel.w = Short4(0xFFFFu);
John Bauman89401822014-05-06 15:04:28 -04001116 break;
1117 case FORMAT_A16B16G16R16:
Maxime Grégoired9762742015-07-08 16:43:48 -04001118 buffer = cBuffer;
John Bauman19bac1e2014-05-06 15:23:49 -04001119 pixel.x = *Pointer<Short4>(buffer + 8 * x);
1120 pixel.y = *Pointer<Short4>(buffer + 8 * x + 8);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001121 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
John Bauman19bac1e2014-05-06 15:23:49 -04001122 pixel.z = *Pointer<Short4>(buffer + 8 * x);
1123 pixel.w = *Pointer<Short4>(buffer + 8 * x + 8);
1124 transpose4x4(pixel.x, pixel.y, pixel.z, pixel.w);
John Bauman89401822014-05-06 15:04:28 -04001125 break;
1126 case FORMAT_G16R16:
1127 buffer = cBuffer;
Maxime Grégoired9762742015-07-08 16:43:48 -04001128 pixel.x = *Pointer<Short4>(buffer + 4 * x);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001129 buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
Maxime Grégoired9762742015-07-08 16:43:48 -04001130 pixel.y = *Pointer<Short4>(buffer + 4 * x);
John Bauman19bac1e2014-05-06 15:23:49 -04001131 pixel.z = pixel.x;
1132 pixel.x = As<Short4>(UnpackLow(pixel.x, pixel.y));
1133 pixel.z = As<Short4>(UnpackHigh(pixel.z, pixel.y));
1134 pixel.y = pixel.z;
1135 pixel.x = As<Short4>(UnpackLow(pixel.x, pixel.z));
1136 pixel.y = As<Short4>(UnpackHigh(pixel.y, pixel.z));
1137 pixel.z = Short4(0xFFFFu);
1138 pixel.w = Short4(0xFFFFu);
John Bauman89401822014-05-06 15:04:28 -04001139 break;
1140 default:
1141 ASSERT(false);
1142 }
1143
1144 if(postBlendSRGB && state.writeSRGB)
1145 {
Nicolas Capens4f172c72016-01-13 08:34:30 -05001146 sRGBtoLinear16_12_16(pixel);
John Bauman89401822014-05-06 15:04:28 -04001147 }
Maxime Grégoired9762742015-07-08 16:43:48 -04001148 }
1149
Nicolas Capens4f172c72016-01-13 08:34:30 -05001150 void PixelRoutine::alphaBlend(int index, Pointer<Byte> &cBuffer, Vector4s &current, Int &x)
Maxime Grégoired9762742015-07-08 16:43:48 -04001151 {
1152 if(!state.alphaBlendActive)
1153 {
1154 return;
1155 }
1156
1157 Vector4s pixel;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001158 readPixel(index, cBuffer, x, pixel);
John Bauman89401822014-05-06 15:04:28 -04001159
1160 // Final Color = ObjectColor * SourceBlendFactor + PixelColor * DestinationBlendFactor
Alexis Hetu96517182015-04-15 10:30:23 -04001161 Vector4s sourceFactor;
1162 Vector4s destFactor;
John Bauman89401822014-05-06 15:04:28 -04001163
Nicolas Capens4f172c72016-01-13 08:34:30 -05001164 blendFactor(sourceFactor, current, pixel, state.sourceBlendFactor);
1165 blendFactor(destFactor, current, pixel, state.destBlendFactor);
John Bauman89401822014-05-06 15:04:28 -04001166
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001167 if(state.sourceBlendFactor != BLEND_ONE && state.sourceBlendFactor != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04001168 {
John Bauman19bac1e2014-05-06 15:23:49 -04001169 current.x = MulHigh(As<UShort4>(current.x), As<UShort4>(sourceFactor.x));
1170 current.y = MulHigh(As<UShort4>(current.y), As<UShort4>(sourceFactor.y));
1171 current.z = MulHigh(As<UShort4>(current.z), As<UShort4>(sourceFactor.z));
John Bauman89401822014-05-06 15:04:28 -04001172 }
Nicolas Capens05b3d662016-02-25 23:58:33 -05001173
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001174 if(state.destBlendFactor != BLEND_ONE && state.destBlendFactor != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04001175 {
John Bauman19bac1e2014-05-06 15:23:49 -04001176 pixel.x = MulHigh(As<UShort4>(pixel.x), As<UShort4>(destFactor.x));
1177 pixel.y = MulHigh(As<UShort4>(pixel.y), As<UShort4>(destFactor.y));
1178 pixel.z = MulHigh(As<UShort4>(pixel.z), As<UShort4>(destFactor.z));
John Bauman89401822014-05-06 15:04:28 -04001179 }
1180
1181 switch(state.blendOperation)
1182 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001183 case BLENDOP_ADD:
John Bauman19bac1e2014-05-06 15:23:49 -04001184 current.x = AddSat(As<UShort4>(current.x), As<UShort4>(pixel.x));
1185 current.y = AddSat(As<UShort4>(current.y), As<UShort4>(pixel.y));
1186 current.z = AddSat(As<UShort4>(current.z), As<UShort4>(pixel.z));
John Bauman89401822014-05-06 15:04:28 -04001187 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001188 case BLENDOP_SUB:
John Bauman19bac1e2014-05-06 15:23:49 -04001189 current.x = SubSat(As<UShort4>(current.x), As<UShort4>(pixel.x));
1190 current.y = SubSat(As<UShort4>(current.y), As<UShort4>(pixel.y));
1191 current.z = SubSat(As<UShort4>(current.z), As<UShort4>(pixel.z));
John Bauman89401822014-05-06 15:04:28 -04001192 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001193 case BLENDOP_INVSUB:
John Bauman19bac1e2014-05-06 15:23:49 -04001194 current.x = SubSat(As<UShort4>(pixel.x), As<UShort4>(current.x));
1195 current.y = SubSat(As<UShort4>(pixel.y), As<UShort4>(current.y));
1196 current.z = SubSat(As<UShort4>(pixel.z), As<UShort4>(current.z));
John Bauman89401822014-05-06 15:04:28 -04001197 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001198 case BLENDOP_MIN:
John Bauman19bac1e2014-05-06 15:23:49 -04001199 current.x = Min(As<UShort4>(current.x), As<UShort4>(pixel.x));
1200 current.y = Min(As<UShort4>(current.y), As<UShort4>(pixel.y));
1201 current.z = Min(As<UShort4>(current.z), As<UShort4>(pixel.z));
John Bauman89401822014-05-06 15:04:28 -04001202 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001203 case BLENDOP_MAX:
John Bauman19bac1e2014-05-06 15:23:49 -04001204 current.x = Max(As<UShort4>(current.x), As<UShort4>(pixel.x));
1205 current.y = Max(As<UShort4>(current.y), As<UShort4>(pixel.y));
1206 current.z = Max(As<UShort4>(current.z), As<UShort4>(pixel.z));
John Bauman89401822014-05-06 15:04:28 -04001207 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001208 case BLENDOP_SOURCE:
John Bauman89401822014-05-06 15:04:28 -04001209 // No operation
1210 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001211 case BLENDOP_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -04001212 current.x = pixel.x;
1213 current.y = pixel.y;
1214 current.z = pixel.z;
John Bauman89401822014-05-06 15:04:28 -04001215 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001216 case BLENDOP_NULL:
John Bauman19bac1e2014-05-06 15:23:49 -04001217 current.x = Short4(0x0000, 0x0000, 0x0000, 0x0000);
1218 current.y = Short4(0x0000, 0x0000, 0x0000, 0x0000);
1219 current.z = Short4(0x0000, 0x0000, 0x0000, 0x0000);
John Bauman89401822014-05-06 15:04:28 -04001220 break;
1221 default:
1222 ASSERT(false);
1223 }
1224
Nicolas Capens4f172c72016-01-13 08:34:30 -05001225 blendFactorAlpha(sourceFactor, current, pixel, state.sourceBlendFactorAlpha);
1226 blendFactorAlpha(destFactor, current, pixel, state.destBlendFactorAlpha);
John Bauman89401822014-05-06 15:04:28 -04001227
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001228 if(state.sourceBlendFactorAlpha != BLEND_ONE && state.sourceBlendFactorAlpha != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04001229 {
John Bauman19bac1e2014-05-06 15:23:49 -04001230 current.w = MulHigh(As<UShort4>(current.w), As<UShort4>(sourceFactor.w));
John Bauman89401822014-05-06 15:04:28 -04001231 }
Nicolas Capens05b3d662016-02-25 23:58:33 -05001232
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001233 if(state.destBlendFactorAlpha != BLEND_ONE && state.destBlendFactorAlpha != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04001234 {
John Bauman19bac1e2014-05-06 15:23:49 -04001235 pixel.w = MulHigh(As<UShort4>(pixel.w), As<UShort4>(destFactor.w));
John Bauman89401822014-05-06 15:04:28 -04001236 }
1237
1238 switch(state.blendOperationAlpha)
1239 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001240 case BLENDOP_ADD:
John Bauman19bac1e2014-05-06 15:23:49 -04001241 current.w = AddSat(As<UShort4>(current.w), As<UShort4>(pixel.w));
John Bauman89401822014-05-06 15:04:28 -04001242 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001243 case BLENDOP_SUB:
John Bauman19bac1e2014-05-06 15:23:49 -04001244 current.w = SubSat(As<UShort4>(current.w), As<UShort4>(pixel.w));
John Bauman89401822014-05-06 15:04:28 -04001245 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001246 case BLENDOP_INVSUB:
John Bauman19bac1e2014-05-06 15:23:49 -04001247 current.w = SubSat(As<UShort4>(pixel.w), As<UShort4>(current.w));
John Bauman89401822014-05-06 15:04:28 -04001248 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001249 case BLENDOP_MIN:
John Bauman19bac1e2014-05-06 15:23:49 -04001250 current.w = Min(As<UShort4>(current.w), As<UShort4>(pixel.w));
John Bauman89401822014-05-06 15:04:28 -04001251 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001252 case BLENDOP_MAX:
John Bauman19bac1e2014-05-06 15:23:49 -04001253 current.w = Max(As<UShort4>(current.w), As<UShort4>(pixel.w));
John Bauman89401822014-05-06 15:04:28 -04001254 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001255 case BLENDOP_SOURCE:
John Bauman89401822014-05-06 15:04:28 -04001256 // No operation
1257 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001258 case BLENDOP_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -04001259 current.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001260 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001261 case BLENDOP_NULL:
John Bauman19bac1e2014-05-06 15:23:49 -04001262 current.w = Short4(0x0000, 0x0000, 0x0000, 0x0000);
John Bauman89401822014-05-06 15:04:28 -04001263 break;
1264 default:
1265 ASSERT(false);
1266 }
1267 }
1268
Nicolas Capens4f172c72016-01-13 08:34:30 -05001269 void PixelRoutine::logicOperation(int index, Pointer<Byte> &cBuffer, Vector4s &current, Int &x)
Maxime Grégoired9762742015-07-08 16:43:48 -04001270 {
Nicolas Capens2afcc802015-08-04 10:34:43 -04001271 if(state.logicalOperation == LOGICALOP_COPY)
Maxime Grégoired9762742015-07-08 16:43:48 -04001272 {
1273 return;
1274 }
1275
1276 Vector4s pixel;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001277 readPixel(index, cBuffer, x, pixel);
Maxime Grégoired9762742015-07-08 16:43:48 -04001278
1279 switch(state.logicalOperation)
1280 {
1281 case LOGICALOP_CLEAR:
1282 current.x = 0;
1283 current.y = 0;
1284 current.z = 0;
1285 break;
1286 case LOGICALOP_SET:
Nicolas Capens2afcc802015-08-04 10:34:43 -04001287 current.x = 0xFFFFu;
1288 current.y = 0xFFFFu;
1289 current.z = 0xFFFFu;
Maxime Grégoired9762742015-07-08 16:43:48 -04001290 break;
1291 case LOGICALOP_COPY:
1292 ASSERT(false); // Optimized out
1293 break;
1294 case LOGICALOP_COPY_INVERTED:
1295 current.x = ~current.x;
1296 current.y = ~current.y;
1297 current.z = ~current.z;
1298 break;
1299 case LOGICALOP_NOOP:
1300 current.x = pixel.x;
1301 current.y = pixel.y;
1302 current.z = pixel.z;
1303 break;
1304 case LOGICALOP_INVERT:
1305 current.x = ~pixel.x;
1306 current.y = ~pixel.y;
1307 current.z = ~pixel.z;
1308 break;
1309 case LOGICALOP_AND:
1310 current.x = pixel.x & current.x;
1311 current.y = pixel.y & current.y;
1312 current.z = pixel.z & current.z;
1313 break;
1314 case LOGICALOP_NAND:
1315 current.x = ~(pixel.x & current.x);
1316 current.y = ~(pixel.y & current.y);
1317 current.z = ~(pixel.z & current.z);
1318 break;
1319 case LOGICALOP_OR:
1320 current.x = pixel.x | current.x;
1321 current.y = pixel.y | current.y;
1322 current.z = pixel.z | current.z;
1323 break;
1324 case LOGICALOP_NOR:
1325 current.x = ~(pixel.x | current.x);
1326 current.y = ~(pixel.y | current.y);
1327 current.z = ~(pixel.z | current.z);
1328 break;
1329 case LOGICALOP_XOR:
1330 current.x = pixel.x ^ current.x;
1331 current.y = pixel.y ^ current.y;
1332 current.z = pixel.z ^ current.z;
1333 break;
1334 case LOGICALOP_EQUIV:
1335 current.x = ~(pixel.x ^ current.x);
1336 current.y = ~(pixel.y ^ current.y);
1337 current.z = ~(pixel.z ^ current.z);
1338 break;
1339 case LOGICALOP_AND_REVERSE:
1340 current.x = ~pixel.x & current.x;
1341 current.y = ~pixel.y & current.y;
1342 current.z = ~pixel.z & current.z;
1343 break;
1344 case LOGICALOP_AND_INVERTED:
1345 current.x = pixel.x & ~current.x;
1346 current.y = pixel.y & ~current.y;
1347 current.z = pixel.z & ~current.z;
1348 break;
1349 case LOGICALOP_OR_REVERSE:
1350 current.x = ~pixel.x | current.x;
1351 current.y = ~pixel.y | current.y;
1352 current.z = ~pixel.z | current.z;
1353 break;
1354 case LOGICALOP_OR_INVERTED:
1355 current.x = pixel.x | ~current.x;
1356 current.y = pixel.y | ~current.y;
1357 current.z = pixel.z | ~current.z;
1358 break;
1359 default:
1360 ASSERT(false);
1361 }
1362 }
1363
Nicolas Capens4f172c72016-01-13 08:34:30 -05001364 void PixelRoutine::writeColor(int index, Pointer<Byte> &cBuffer, Int &x, Vector4s &current, Int &sMask, Int &zMask, Int &cMask)
John Bauman89401822014-05-06 15:04:28 -04001365 {
John Bauman89401822014-05-06 15:04:28 -04001366 if(postBlendSRGB && state.writeSRGB)
1367 {
Nicolas Capens4f172c72016-01-13 08:34:30 -05001368 linearToSRGB16_12_16(current);
John Bauman89401822014-05-06 15:04:28 -04001369 }
1370
1371 if(exactColorRounding)
1372 {
1373 switch(state.targetFormat[index])
1374 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001375 case FORMAT_R5G6B5:
Nicolas Capens26f37222015-09-22 09:53:45 -04001376 current.x = AddSat(As<UShort4>(current.x), UShort4(0x0400));
1377 current.y = AddSat(As<UShort4>(current.y), UShort4(0x0200));
1378 current.z = AddSat(As<UShort4>(current.z), UShort4(0x0400));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001379 break;
John Bauman89401822014-05-06 15:04:28 -04001380 case FORMAT_X8G8R8B8Q:
1381 case FORMAT_A8G8R8B8Q:
1382 case FORMAT_X8R8G8B8:
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001383 case FORMAT_X8B8G8R8:
John Bauman89401822014-05-06 15:04:28 -04001384 case FORMAT_A8R8G8B8:
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001385 case FORMAT_A8B8G8R8:
Nicolas Capens26f37222015-09-22 09:53:45 -04001386 current.x = current.x - As<Short4>(As<UShort4>(current.x) >> 8) + Short4(0x0080, 0x0080, 0x0080, 0x0080);
1387 current.y = current.y - As<Short4>(As<UShort4>(current.y) >> 8) + Short4(0x0080, 0x0080, 0x0080, 0x0080);
1388 current.z = current.z - As<Short4>(As<UShort4>(current.z) >> 8) + Short4(0x0080, 0x0080, 0x0080, 0x0080);
1389 current.w = current.w - As<Short4>(As<UShort4>(current.w) >> 8) + Short4(0x0080, 0x0080, 0x0080, 0x0080);
John Bauman89401822014-05-06 15:04:28 -04001390 break;
Nicolas Capensb69aa272016-01-02 00:06:41 -05001391 default:
1392 break;
John Bauman89401822014-05-06 15:04:28 -04001393 }
1394 }
1395
1396 int rgbaWriteMask = state.colorWriteActive(index);
Nicolas Capens3b396462016-01-02 00:23:53 -05001397 int bgraWriteMask = (rgbaWriteMask & 0x0000000A) | (rgbaWriteMask & 0x00000001) << 2 | (rgbaWriteMask & 0x00000004) >> 2;
1398 int brgaWriteMask = (rgbaWriteMask & 0x00000008) | (rgbaWriteMask & 0x00000001) << 1 | (rgbaWriteMask & 0x00000002) << 1 | (rgbaWriteMask & 0x00000004) >> 2;
John Bauman89401822014-05-06 15:04:28 -04001399
1400 switch(state.targetFormat[index])
1401 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001402 case FORMAT_R5G6B5:
1403 {
1404 current.x = current.x & Short4(0xF800u);
1405 current.y = As<UShort4>(current.y & Short4(0xFC00u)) >> 5;
1406 current.z = As<UShort4>(current.z) >> 11;
1407
1408 current.x = current.x | current.y | current.z;
1409 }
1410 break;
John Bauman89401822014-05-06 15:04:28 -04001411 case FORMAT_X8G8R8B8Q:
1412 UNIMPLEMENTED();
John Bauman19bac1e2014-05-06 15:23:49 -04001413 // current.x = As<Short4>(As<UShort4>(current.x) >> 8);
1414 // current.y = As<Short4>(As<UShort4>(current.y) >> 8);
1415 // current.z = As<Short4>(As<UShort4>(current.z) >> 8);
John Bauman89401822014-05-06 15:04:28 -04001416
John Bauman19bac1e2014-05-06 15:23:49 -04001417 // current.z = As<Short4>(Pack(As<UShort4>(current.z), As<UShort4>(current.x)));
1418 // current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.y)));
John Bauman89401822014-05-06 15:04:28 -04001419 break;
1420 case FORMAT_A8G8R8B8Q:
1421 UNIMPLEMENTED();
John Bauman19bac1e2014-05-06 15:23:49 -04001422 // current.x = As<Short4>(As<UShort4>(current.x) >> 8);
1423 // current.y = As<Short4>(As<UShort4>(current.y) >> 8);
1424 // current.z = As<Short4>(As<UShort4>(current.z) >> 8);
1425 // current.w = As<Short4>(As<UShort4>(current.w) >> 8);
John Bauman89401822014-05-06 15:04:28 -04001426
John Bauman19bac1e2014-05-06 15:23:49 -04001427 // current.z = As<Short4>(Pack(As<UShort4>(current.z), As<UShort4>(current.x)));
1428 // current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.w)));
John Bauman89401822014-05-06 15:04:28 -04001429 break;
1430 case FORMAT_X8R8G8B8:
1431 case FORMAT_A8R8G8B8:
1432 if(state.targetFormat[index] == FORMAT_X8R8G8B8 || rgbaWriteMask == 0x7)
1433 {
John Bauman19bac1e2014-05-06 15:23:49 -04001434 current.x = As<Short4>(As<UShort4>(current.x) >> 8);
1435 current.y = As<Short4>(As<UShort4>(current.y) >> 8);
1436 current.z = As<Short4>(As<UShort4>(current.z) >> 8);
John Bauman89401822014-05-06 15:04:28 -04001437
John Bauman19bac1e2014-05-06 15:23:49 -04001438 current.z = As<Short4>(Pack(As<UShort4>(current.z), As<UShort4>(current.x)));
1439 current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.y)));
John Bauman89401822014-05-06 15:04:28 -04001440
John Bauman19bac1e2014-05-06 15:23:49 -04001441 current.x = current.z;
1442 current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
1443 current.x = UnpackHigh(As<Byte8>(current.x), As<Byte8>(current.y));
1444 current.y = current.z;
1445 current.z = As<Short4>(UnpackLow(current.z, current.x));
1446 current.y = As<Short4>(UnpackHigh(current.y, current.x));
John Bauman89401822014-05-06 15:04:28 -04001447 }
1448 else
1449 {
John Bauman19bac1e2014-05-06 15:23:49 -04001450 current.x = As<Short4>(As<UShort4>(current.x) >> 8);
1451 current.y = As<Short4>(As<UShort4>(current.y) >> 8);
1452 current.z = As<Short4>(As<UShort4>(current.z) >> 8);
1453 current.w = As<Short4>(As<UShort4>(current.w) >> 8);
John Bauman89401822014-05-06 15:04:28 -04001454
John Bauman19bac1e2014-05-06 15:23:49 -04001455 current.z = As<Short4>(Pack(As<UShort4>(current.z), As<UShort4>(current.x)));
1456 current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.w)));
John Bauman89401822014-05-06 15:04:28 -04001457
John Bauman19bac1e2014-05-06 15:23:49 -04001458 current.x = current.z;
1459 current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
1460 current.x = UnpackHigh(As<Byte8>(current.x), As<Byte8>(current.y));
1461 current.y = current.z;
1462 current.z = As<Short4>(UnpackLow(current.z, current.x));
1463 current.y = As<Short4>(UnpackHigh(current.y, current.x));
John Bauman89401822014-05-06 15:04:28 -04001464 }
1465 break;
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001466 case FORMAT_X8B8G8R8:
1467 case FORMAT_A8B8G8R8:
1468 if(state.targetFormat[index] == FORMAT_X8B8G8R8 || rgbaWriteMask == 0x7)
1469 {
1470 current.x = As<Short4>(As<UShort4>(current.x) >> 8);
1471 current.y = As<Short4>(As<UShort4>(current.y) >> 8);
1472 current.z = As<Short4>(As<UShort4>(current.z) >> 8);
1473
1474 current.z = As<Short4>(Pack(As<UShort4>(current.x), As<UShort4>(current.z)));
1475 current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.y)));
1476
1477 current.x = current.z;
1478 current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
1479 current.x = UnpackHigh(As<Byte8>(current.x), As<Byte8>(current.y));
1480 current.y = current.z;
1481 current.z = As<Short4>(UnpackLow(current.z, current.x));
1482 current.y = As<Short4>(UnpackHigh(current.y, current.x));
1483 }
1484 else
1485 {
1486 current.x = As<Short4>(As<UShort4>(current.x) >> 8);
1487 current.y = As<Short4>(As<UShort4>(current.y) >> 8);
1488 current.z = As<Short4>(As<UShort4>(current.z) >> 8);
1489 current.w = As<Short4>(As<UShort4>(current.w) >> 8);
1490
1491 current.z = As<Short4>(Pack(As<UShort4>(current.x), As<UShort4>(current.z)));
1492 current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.w)));
1493
1494 current.x = current.z;
1495 current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
1496 current.x = UnpackHigh(As<Byte8>(current.x), As<Byte8>(current.y));
1497 current.y = current.z;
1498 current.z = As<Short4>(UnpackLow(current.z, current.x));
1499 current.y = As<Short4>(UnpackHigh(current.y, current.x));
1500 }
1501 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001502 case FORMAT_A8:
1503 current.w = As<Short4>(As<UShort4>(current.w) >> 8);
1504 current.w = As<Short4>(Pack(As<UShort4>(current.w), As<UShort4>(current.w)));
1505 break;
John Bauman89401822014-05-06 15:04:28 -04001506 case FORMAT_G16R16:
John Bauman19bac1e2014-05-06 15:23:49 -04001507 current.z = current.x;
1508 current.x = As<Short4>(UnpackLow(current.x, current.y));
1509 current.z = As<Short4>(UnpackHigh(current.z, current.y));
1510 current.y = current.z;
John Bauman89401822014-05-06 15:04:28 -04001511 break;
1512 case FORMAT_A16B16G16R16:
John Bauman19bac1e2014-05-06 15:23:49 -04001513 transpose4x4(current.x, current.y, current.z, current.w);
John Bauman89401822014-05-06 15:04:28 -04001514 break;
John Bauman89401822014-05-06 15:04:28 -04001515 default:
1516 ASSERT(false);
1517 }
1518
John Bauman19bac1e2014-05-06 15:23:49 -04001519 Short4 c01 = current.z;
1520 Short4 c23 = current.y;
John Bauman89401822014-05-06 15:04:28 -04001521
1522 Int xMask; // Combination of all masks
1523
1524 if(state.depthTestActive)
1525 {
1526 xMask = zMask;
1527 }
1528 else
1529 {
1530 xMask = cMask;
1531 }
1532
1533 if(state.stencilActive)
1534 {
1535 xMask &= sMask;
1536 }
1537
John Bauman89401822014-05-06 15:04:28 -04001538 switch(state.targetFormat[index])
1539 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001540 case FORMAT_R5G6B5:
1541 {
1542 Pointer<Byte> buffer = cBuffer + 2 * x;
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001543 Int value = *Pointer<Int>(buffer);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001544
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001545 Int c01 = Extract(As<Int2>(current.x), 0);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001546
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001547 if((bgraWriteMask & 0x00000007) != 0x00000007)
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001548 {
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001549 Int masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001550 c01 &= *Pointer<Int>(constants + OFFSET(Constants,mask565Q[bgraWriteMask & 0x7][0]));
1551 masked &= *Pointer<Int>(constants + OFFSET(Constants,invMask565Q[bgraWriteMask & 0x7][0]));
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001552 c01 |= masked;
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001553 }
1554
Nicolas Capens4f172c72016-01-13 08:34:30 -05001555 c01 &= *Pointer<Int>(constants + OFFSET(Constants,maskW4Q[0][0]) + xMask * 8);
1556 value &= *Pointer<Int>(constants + OFFSET(Constants,invMaskW4Q[0][0]) + xMask * 8);
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001557 c01 |= value;
1558 *Pointer<Int>(buffer) = c01;
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001559
Nicolas Capens4f172c72016-01-13 08:34:30 -05001560 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001561 value = *Pointer<Int>(buffer);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001562
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001563 Int c23 = Extract(As<Int2>(current.x), 1);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001564
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001565 if((bgraWriteMask & 0x00000007) != 0x00000007)
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001566 {
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001567 Int masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001568 c23 &= *Pointer<Int>(constants + OFFSET(Constants,mask565Q[bgraWriteMask & 0x7][0]));
1569 masked &= *Pointer<Int>(constants + OFFSET(Constants,invMask565Q[bgraWriteMask & 0x7][0]));
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001570 c23 |= masked;
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001571 }
1572
Nicolas Capens4f172c72016-01-13 08:34:30 -05001573 c23 &= *Pointer<Int>(constants + OFFSET(Constants,maskW4Q[0][2]) + xMask * 8);
1574 value &= *Pointer<Int>(constants + OFFSET(Constants,invMaskW4Q[0][2]) + xMask * 8);
Nicolas Capens9919b6c2015-05-26 01:11:26 -04001575 c23 |= value;
1576 *Pointer<Int>(buffer) = c23;
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001577 }
1578 break;
John Bauman89401822014-05-06 15:04:28 -04001579 case FORMAT_A8G8R8B8Q:
1580 case FORMAT_X8G8R8B8Q: // FIXME: Don't touch alpha?
1581 UNIMPLEMENTED();
1582 // value = *Pointer<Short4>(cBuffer + 8 * x + 0);
1583
1584 // if((state.targetFormat[index] == FORMAT_A8G8R8B8Q && bgraWriteMask != 0x0000000F) ||
1585 // ((state.targetFormat[index] == FORMAT_X8G8R8B8Q && bgraWriteMask != 0x00000007) &&
1586 // (state.targetFormat[index] == FORMAT_X8G8R8B8Q && bgraWriteMask != 0x0000000F))) // FIXME: Need for masking when XRGB && Fh?
1587 // {
1588 // Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001589 // c01 &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q[bgraWriteMask][0]));
1590 // masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q[bgraWriteMask][0]));
John Bauman89401822014-05-06 15:04:28 -04001591 // c01 |= masked;
1592 // }
1593
Nicolas Capens4f172c72016-01-13 08:34:30 -05001594 // c01 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD01Q) + xMask * 8);
1595 // value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD01Q) + xMask * 8);
John Bauman89401822014-05-06 15:04:28 -04001596 // c01 |= value;
1597 // *Pointer<Short4>(cBuffer + 8 * x + 0) = c01;
1598
1599 // value = *Pointer<Short4>(cBuffer + 8 * x + 8);
1600
1601 // if((state.targetFormat[index] == FORMAT_A8G8R8B8Q && bgraWriteMask != 0x0000000F) ||
1602 // ((state.targetFormat[index] == FORMAT_X8G8R8B8Q && bgraWriteMask != 0x00000007) &&
1603 // (state.targetFormat[index] == FORMAT_X8G8R8B8Q && bgraWriteMask != 0x0000000F))) // FIXME: Need for masking when XRGB && Fh?
1604 // {
1605 // Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001606 // c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q[bgraWriteMask][0]));
1607 // masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q[bgraWriteMask][0]));
John Bauman89401822014-05-06 15:04:28 -04001608 // c23 |= masked;
1609 // }
1610
Nicolas Capens4f172c72016-01-13 08:34:30 -05001611 // c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD23Q) + xMask * 8);
1612 // value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD23Q) + xMask * 8);
John Bauman89401822014-05-06 15:04:28 -04001613 // c23 |= value;
1614 // *Pointer<Short4>(cBuffer + 8 * x + 8) = c23;
1615 break;
1616 case FORMAT_A8R8G8B8:
1617 case FORMAT_X8R8G8B8: // FIXME: Don't touch alpha?
John Bauman89401822014-05-06 15:04:28 -04001618 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001619 Pointer<Byte> buffer = cBuffer + x * 4;
1620 Short4 value = *Pointer<Short4>(buffer);
1621
1622 if((state.targetFormat[index] == FORMAT_A8R8G8B8 && bgraWriteMask != 0x0000000F) ||
1623 ((state.targetFormat[index] == FORMAT_X8R8G8B8 && bgraWriteMask != 0x00000007) &&
1624 (state.targetFormat[index] == FORMAT_X8R8G8B8 && bgraWriteMask != 0x0000000F))) // FIXME: Need for masking when XRGB && Fh?
1625 {
1626 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001627 c01 &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q[bgraWriteMask][0]));
1628 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q[bgraWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001629 c01 |= masked;
1630 }
1631
Nicolas Capens4f172c72016-01-13 08:34:30 -05001632 c01 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD01Q) + xMask * 8);
1633 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD01Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001634 c01 |= value;
1635 *Pointer<Short4>(buffer) = c01;
1636
Nicolas Capens4f172c72016-01-13 08:34:30 -05001637 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001638 value = *Pointer<Short4>(buffer);
1639
1640 if((state.targetFormat[index] == FORMAT_A8R8G8B8 && bgraWriteMask != 0x0000000F) ||
1641 ((state.targetFormat[index] == FORMAT_X8R8G8B8 && bgraWriteMask != 0x00000007) &&
1642 (state.targetFormat[index] == FORMAT_X8R8G8B8 && bgraWriteMask != 0x0000000F))) // FIXME: Need for masking when XRGB && Fh?
1643 {
1644 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001645 c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q[bgraWriteMask][0]));
1646 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q[bgraWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001647 c23 |= masked;
1648 }
1649
Nicolas Capens4f172c72016-01-13 08:34:30 -05001650 c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD23Q) + xMask * 8);
1651 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD23Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001652 c23 |= value;
1653 *Pointer<Short4>(buffer) = c23;
John Bauman89401822014-05-06 15:04:28 -04001654 }
John Bauman89401822014-05-06 15:04:28 -04001655 break;
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001656 case FORMAT_A8B8G8R8:
1657 case FORMAT_X8B8G8R8: // FIXME: Don't touch alpha?
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001658 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001659 Pointer<Byte> buffer = cBuffer + x * 4;
1660 Short4 value = *Pointer<Short4>(buffer);
1661
1662 if((state.targetFormat[index] == FORMAT_A8B8G8R8 && rgbaWriteMask != 0x0000000F) ||
1663 ((state.targetFormat[index] == FORMAT_X8B8G8R8 && rgbaWriteMask != 0x00000007) &&
1664 (state.targetFormat[index] == FORMAT_X8B8G8R8 && rgbaWriteMask != 0x0000000F))) // FIXME: Need for masking when XBGR && Fh?
1665 {
1666 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001667 c01 &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q[rgbaWriteMask][0]));
1668 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q[rgbaWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001669 c01 |= masked;
1670 }
1671
Nicolas Capens4f172c72016-01-13 08:34:30 -05001672 c01 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD01Q) + xMask * 8);
1673 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD01Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001674 c01 |= value;
1675 *Pointer<Short4>(buffer) = c01;
1676
Nicolas Capens4f172c72016-01-13 08:34:30 -05001677 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001678 value = *Pointer<Short4>(buffer);
1679
1680 if((state.targetFormat[index] == FORMAT_A8B8G8R8 && rgbaWriteMask != 0x0000000F) ||
1681 ((state.targetFormat[index] == FORMAT_X8B8G8R8 && rgbaWriteMask != 0x00000007) &&
1682 (state.targetFormat[index] == FORMAT_X8B8G8R8 && rgbaWriteMask != 0x0000000F))) // FIXME: Need for masking when XBGR && Fh?
1683 {
1684 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001685 c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q[rgbaWriteMask][0]));
1686 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q[rgbaWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001687 c23 |= masked;
1688 }
1689
Nicolas Capens4f172c72016-01-13 08:34:30 -05001690 c23 &= *Pointer<Short4>(constants + OFFSET(Constants,maskD23Q) + xMask * 8);
1691 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD23Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001692 c23 |= value;
1693 *Pointer<Short4>(buffer) = c23;
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001694 }
Nicolas Capens0c42ee12015-03-28 18:54:07 -04001695 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001696 case FORMAT_A8:
1697 if(rgbaWriteMask & 0x00000008)
1698 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001699 Pointer<Byte> buffer = cBuffer + 1 * x;
1700 Short4 value;
John Bauman66b8ab22014-05-06 15:57:45 -04001701 Insert(value, *Pointer<Short>(buffer), 0);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001702 Int pitch = *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman66b8ab22014-05-06 15:57:45 -04001703 Insert(value, *Pointer<Short>(buffer + pitch), 1);
1704 value = UnpackLow(As<Byte8>(value), As<Byte8>(value));
1705
Nicolas Capens4f172c72016-01-13 08:34:30 -05001706 current.w &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q) + 8 * xMask);
1707 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q) + 8 * xMask);
John Bauman66b8ab22014-05-06 15:57:45 -04001708 current.w |= value;
1709
1710 *Pointer<Short>(buffer) = Extract(current.w, 0);
1711 *Pointer<Short>(buffer + pitch) = Extract(current.w, 1);
1712 }
1713 break;
John Bauman89401822014-05-06 15:04:28 -04001714 case FORMAT_G16R16:
John Bauman89401822014-05-06 15:04:28 -04001715 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001716 Pointer<Byte> buffer = cBuffer + 4 * x;
John Bauman89401822014-05-06 15:04:28 -04001717
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001718 Short4 value = *Pointer<Short4>(buffer);
John Bauman89401822014-05-06 15:04:28 -04001719
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001720 if((rgbaWriteMask & 0x00000003) != 0x00000003)
John Bauman89401822014-05-06 15:04:28 -04001721 {
1722 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001723 current.x &= *Pointer<Short4>(constants + OFFSET(Constants,maskW01Q[rgbaWriteMask & 0x3][0]));
1724 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskW01Q[rgbaWriteMask & 0x3][0]));
John Bauman19bac1e2014-05-06 15:23:49 -04001725 current.x |= masked;
John Bauman89401822014-05-06 15:04:28 -04001726 }
1727
Nicolas Capens4f172c72016-01-13 08:34:30 -05001728 current.x &= *Pointer<Short4>(constants + OFFSET(Constants,maskD01Q) + xMask * 8);
1729 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD01Q) + xMask * 8);
John Bauman19bac1e2014-05-06 15:23:49 -04001730 current.x |= value;
1731 *Pointer<Short4>(buffer) = current.x;
John Bauman89401822014-05-06 15:04:28 -04001732
Nicolas Capens4f172c72016-01-13 08:34:30 -05001733 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04001734
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001735 value = *Pointer<Short4>(buffer);
1736
1737 if((rgbaWriteMask & 0x00000003) != 0x00000003)
John Bauman89401822014-05-06 15:04:28 -04001738 {
1739 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001740 current.y &= *Pointer<Short4>(constants + OFFSET(Constants,maskW01Q[rgbaWriteMask & 0x3][0]));
1741 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskW01Q[rgbaWriteMask & 0x3][0]));
John Bauman19bac1e2014-05-06 15:23:49 -04001742 current.y |= masked;
John Bauman89401822014-05-06 15:04:28 -04001743 }
1744
Nicolas Capens4f172c72016-01-13 08:34:30 -05001745 current.y &= *Pointer<Short4>(constants + OFFSET(Constants,maskD23Q) + xMask * 8);
1746 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskD23Q) + xMask * 8);
John Bauman19bac1e2014-05-06 15:23:49 -04001747 current.y |= value;
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001748 *Pointer<Short4>(buffer) = current.y;
John Bauman89401822014-05-06 15:04:28 -04001749 }
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001750 break;
1751 case FORMAT_A16B16G16R16:
John Bauman89401822014-05-06 15:04:28 -04001752 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001753 Pointer<Byte> buffer = cBuffer + 8 * x;
John Bauman89401822014-05-06 15:04:28 -04001754
John Bauman89401822014-05-06 15:04:28 -04001755 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001756 Short4 value = *Pointer<Short4>(buffer);
1757
1758 if(rgbaWriteMask != 0x0000000F)
1759 {
1760 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001761 current.x &= *Pointer<Short4>(constants + OFFSET(Constants,maskW4Q[rgbaWriteMask][0]));
1762 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskW4Q[rgbaWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001763 current.x |= masked;
1764 }
1765
Nicolas Capens4f172c72016-01-13 08:34:30 -05001766 current.x &= *Pointer<Short4>(constants + OFFSET(Constants,maskQ0Q) + xMask * 8);
1767 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskQ0Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001768 current.x |= value;
1769 *Pointer<Short4>(buffer) = current.x;
John Bauman89401822014-05-06 15:04:28 -04001770 }
1771
John Bauman89401822014-05-06 15:04:28 -04001772 {
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001773 Short4 value = *Pointer<Short4>(buffer + 8);
1774
1775 if(rgbaWriteMask != 0x0000000F)
1776 {
1777 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001778 current.y &= *Pointer<Short4>(constants + OFFSET(Constants,maskW4Q[rgbaWriteMask][0]));
1779 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskW4Q[rgbaWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001780 current.y |= masked;
1781 }
1782
Nicolas Capens4f172c72016-01-13 08:34:30 -05001783 current.y &= *Pointer<Short4>(constants + OFFSET(Constants,maskQ1Q) + xMask * 8);
1784 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskQ1Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001785 current.y |= value;
1786 *Pointer<Short4>(buffer + 8) = current.y;
John Bauman89401822014-05-06 15:04:28 -04001787 }
1788
Nicolas Capens4f172c72016-01-13 08:34:30 -05001789 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001790
1791 {
1792 Short4 value = *Pointer<Short4>(buffer);
1793
1794 if(rgbaWriteMask != 0x0000000F)
1795 {
1796 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001797 current.z &= *Pointer<Short4>(constants + OFFSET(Constants,maskW4Q[rgbaWriteMask][0]));
1798 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskW4Q[rgbaWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001799 current.z |= masked;
1800 }
1801
Nicolas Capens4f172c72016-01-13 08:34:30 -05001802 current.z &= *Pointer<Short4>(constants + OFFSET(Constants,maskQ2Q) + xMask * 8);
1803 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskQ2Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001804 current.z |= value;
1805 *Pointer<Short4>(buffer) = current.z;
1806 }
1807
1808 {
1809 Short4 value = *Pointer<Short4>(buffer + 8);
1810
1811 if(rgbaWriteMask != 0x0000000F)
1812 {
1813 Short4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05001814 current.w &= *Pointer<Short4>(constants + OFFSET(Constants,maskW4Q[rgbaWriteMask][0]));
1815 masked &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskW4Q[rgbaWriteMask][0]));
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001816 current.w |= masked;
1817 }
1818
Nicolas Capens4f172c72016-01-13 08:34:30 -05001819 current.w &= *Pointer<Short4>(constants + OFFSET(Constants,maskQ3Q) + xMask * 8);
1820 value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskQ3Q) + xMask * 8);
Nicolas Capensd5f0a6c2015-05-26 00:18:01 -04001821 current.w |= value;
1822 *Pointer<Short4>(buffer + 8) = current.w;
1823 }
John Bauman89401822014-05-06 15:04:28 -04001824 }
1825 break;
1826 default:
1827 ASSERT(false);
1828 }
1829 }
1830
Nicolas Capens05b3d662016-02-25 23:58:33 -05001831 void PixelRoutine::blendFactor(const Vector4f &blendFactor, const Vector4f &oC, const Vector4f &pixel, BlendFactor blendFactorActive)
John Bauman89401822014-05-06 15:04:28 -04001832 {
1833 switch(blendFactorActive)
1834 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001835 case BLEND_ZERO:
John Bauman89401822014-05-06 15:04:28 -04001836 // Optimized
1837 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001838 case BLEND_ONE:
John Bauman89401822014-05-06 15:04:28 -04001839 // Optimized
1840 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001841 case BLEND_SOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -04001842 blendFactor.x = oC.x;
1843 blendFactor.y = oC.y;
1844 blendFactor.z = oC.z;
John Bauman89401822014-05-06 15:04:28 -04001845 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001846 case BLEND_INVSOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -04001847 blendFactor.x = Float4(1.0f) - oC.x;
1848 blendFactor.y = Float4(1.0f) - oC.y;
1849 blendFactor.z = Float4(1.0f) - oC.z;
John Bauman89401822014-05-06 15:04:28 -04001850 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001851 case BLEND_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -04001852 blendFactor.x = pixel.x;
1853 blendFactor.y = pixel.y;
1854 blendFactor.z = pixel.z;
John Bauman89401822014-05-06 15:04:28 -04001855 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001856 case BLEND_INVDEST:
John Bauman19bac1e2014-05-06 15:23:49 -04001857 blendFactor.x = Float4(1.0f) - pixel.x;
1858 blendFactor.y = Float4(1.0f) - pixel.y;
1859 blendFactor.z = Float4(1.0f) - pixel.z;
John Bauman89401822014-05-06 15:04:28 -04001860 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001861 case BLEND_SOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001862 blendFactor.x = oC.w;
1863 blendFactor.y = oC.w;
1864 blendFactor.z = oC.w;
John Bauman89401822014-05-06 15:04:28 -04001865 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001866 case BLEND_INVSOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001867 blendFactor.x = Float4(1.0f) - oC.w;
1868 blendFactor.y = Float4(1.0f) - oC.w;
1869 blendFactor.z = Float4(1.0f) - oC.w;
John Bauman89401822014-05-06 15:04:28 -04001870 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001871 case BLEND_DESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001872 blendFactor.x = pixel.w;
1873 blendFactor.y = pixel.w;
1874 blendFactor.z = pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001875 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001876 case BLEND_INVDESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001877 blendFactor.x = Float4(1.0f) - pixel.w;
1878 blendFactor.y = Float4(1.0f) - pixel.w;
1879 blendFactor.z = Float4(1.0f) - pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001880 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001881 case BLEND_SRCALPHASAT:
John Bauman19bac1e2014-05-06 15:23:49 -04001882 blendFactor.x = Float4(1.0f) - pixel.w;
1883 blendFactor.x = Min(blendFactor.x, oC.w);
1884 blendFactor.y = blendFactor.x;
1885 blendFactor.z = blendFactor.x;
John Bauman89401822014-05-06 15:04:28 -04001886 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001887 case BLEND_CONSTANT:
Nicolas Capens4f172c72016-01-13 08:34:30 -05001888 blendFactor.x = *Pointer<Float4>(data + OFFSET(DrawData,factor.blendConstant4F[0]));
1889 blendFactor.y = *Pointer<Float4>(data + OFFSET(DrawData,factor.blendConstant4F[1]));
1890 blendFactor.z = *Pointer<Float4>(data + OFFSET(DrawData,factor.blendConstant4F[2]));
John Bauman89401822014-05-06 15:04:28 -04001891 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001892 case BLEND_INVCONSTANT:
Nicolas Capens4f172c72016-01-13 08:34:30 -05001893 blendFactor.x = *Pointer<Float4>(data + OFFSET(DrawData,factor.invBlendConstant4F[0]));
1894 blendFactor.y = *Pointer<Float4>(data + OFFSET(DrawData,factor.invBlendConstant4F[1]));
1895 blendFactor.z = *Pointer<Float4>(data + OFFSET(DrawData,factor.invBlendConstant4F[2]));
John Bauman89401822014-05-06 15:04:28 -04001896 break;
1897 default:
1898 ASSERT(false);
1899 }
1900 }
1901
Nicolas Capens05b3d662016-02-25 23:58:33 -05001902 void PixelRoutine::blendFactorAlpha(const Vector4f &blendFactor, const Vector4f &oC, const Vector4f &pixel, BlendFactor blendFactorAlphaActive)
John Bauman89401822014-05-06 15:04:28 -04001903 {
1904 switch(blendFactorAlphaActive)
1905 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001906 case BLEND_ZERO:
John Bauman89401822014-05-06 15:04:28 -04001907 // Optimized
1908 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001909 case BLEND_ONE:
John Bauman89401822014-05-06 15:04:28 -04001910 // Optimized
1911 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001912 case BLEND_SOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -04001913 blendFactor.w = oC.w;
John Bauman89401822014-05-06 15:04:28 -04001914 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001915 case BLEND_INVSOURCE:
John Bauman19bac1e2014-05-06 15:23:49 -04001916 blendFactor.w = Float4(1.0f) - oC.w;
John Bauman89401822014-05-06 15:04:28 -04001917 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001918 case BLEND_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -04001919 blendFactor.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001920 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001921 case BLEND_INVDEST:
John Bauman19bac1e2014-05-06 15:23:49 -04001922 blendFactor.w = Float4(1.0f) - pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001923 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001924 case BLEND_SOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001925 blendFactor.w = oC.w;
John Bauman89401822014-05-06 15:04:28 -04001926 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001927 case BLEND_INVSOURCEALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001928 blendFactor.w = Float4(1.0f) - oC.w;
John Bauman89401822014-05-06 15:04:28 -04001929 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001930 case BLEND_DESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001931 blendFactor.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001932 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001933 case BLEND_INVDESTALPHA:
John Bauman19bac1e2014-05-06 15:23:49 -04001934 blendFactor.w = Float4(1.0f) - pixel.w;
John Bauman89401822014-05-06 15:04:28 -04001935 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001936 case BLEND_SRCALPHASAT:
John Bauman19bac1e2014-05-06 15:23:49 -04001937 blendFactor.w = Float4(1.0f);
John Bauman89401822014-05-06 15:04:28 -04001938 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001939 case BLEND_CONSTANT:
Nicolas Capens4f172c72016-01-13 08:34:30 -05001940 blendFactor.w = *Pointer<Float4>(data + OFFSET(DrawData,factor.blendConstant4F[3]));
John Bauman89401822014-05-06 15:04:28 -04001941 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001942 case BLEND_INVCONSTANT:
Nicolas Capens4f172c72016-01-13 08:34:30 -05001943 blendFactor.w = *Pointer<Float4>(data + OFFSET(DrawData,factor.invBlendConstant4F[3]));
John Bauman89401822014-05-06 15:04:28 -04001944 break;
1945 default:
1946 ASSERT(false);
1947 }
1948 }
1949
Nicolas Capens4f172c72016-01-13 08:34:30 -05001950 void PixelRoutine::alphaBlend(int index, Pointer<Byte> &cBuffer, Vector4f &oC, Int &x)
John Bauman89401822014-05-06 15:04:28 -04001951 {
1952 if(!state.alphaBlendActive)
1953 {
1954 return;
1955 }
1956
1957 Pointer<Byte> buffer;
John Bauman19bac1e2014-05-06 15:23:49 -04001958 Vector4f pixel;
John Bauman89401822014-05-06 15:04:28 -04001959
Alexis Hetu96517182015-04-15 10:30:23 -04001960 Vector4s color;
John Bauman89401822014-05-06 15:04:28 -04001961 Short4 c01;
1962 Short4 c23;
1963
Alexis Hetu1abb6382016-02-08 11:21:16 -05001964 Float4 one;
John Bauman89401822014-05-06 15:04:28 -04001965 switch(state.targetFormat[index])
1966 {
Alexis Hetu1abb6382016-02-08 11:21:16 -05001967 case FORMAT_R32I:
1968 case FORMAT_G32R32I:
1969 one = As<Float4>(Int4(0x7FFFFFFF));
1970 break;
1971 case FORMAT_R32UI:
1972 case FORMAT_G32R32UI:
1973 one = As<Float4>(Int4(0xFFFFFFFF));
1974 break;
1975 case FORMAT_R32F:
1976 case FORMAT_G32R32F:
1977 one = Float4(1.0f);
1978 break;
1979 }
1980
1981 switch(state.targetFormat[index])
1982 {
1983 case FORMAT_R32I:
1984 case FORMAT_R32UI:
John Bauman89401822014-05-06 15:04:28 -04001985 case FORMAT_R32F:
1986 buffer = cBuffer;
1987 // FIXME: movlps
John Bauman19bac1e2014-05-06 15:23:49 -04001988 pixel.x.x = *Pointer<Float>(buffer + 4 * x + 0);
1989 pixel.x.y = *Pointer<Float>(buffer + 4 * x + 4);
Nicolas Capens4f172c72016-01-13 08:34:30 -05001990 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04001991 // FIXME: movhps
John Bauman19bac1e2014-05-06 15:23:49 -04001992 pixel.x.z = *Pointer<Float>(buffer + 4 * x + 0);
1993 pixel.x.w = *Pointer<Float>(buffer + 4 * x + 4);
Alexis Hetu1abb6382016-02-08 11:21:16 -05001994 pixel.y = pixel.z = pixel.w = one;
John Bauman89401822014-05-06 15:04:28 -04001995 break;
Alexis Hetu1abb6382016-02-08 11:21:16 -05001996 case FORMAT_G32R32I:
1997 case FORMAT_G32R32UI:
John Bauman89401822014-05-06 15:04:28 -04001998 case FORMAT_G32R32F:
1999 buffer = cBuffer;
John Bauman19bac1e2014-05-06 15:23:49 -04002000 pixel.x = *Pointer<Float4>(buffer + 8 * x, 16);
Nicolas Capens4f172c72016-01-13 08:34:30 -05002001 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman19bac1e2014-05-06 15:23:49 -04002002 pixel.y = *Pointer<Float4>(buffer + 8 * x, 16);
2003 pixel.z = pixel.x;
2004 pixel.x = ShuffleLowHigh(pixel.x, pixel.y, 0x88);
2005 pixel.z = ShuffleLowHigh(pixel.z, pixel.y, 0xDD);
2006 pixel.y = pixel.z;
Alexis Hetu1abb6382016-02-08 11:21:16 -05002007 pixel.z = pixel.w = one;
John Bauman89401822014-05-06 15:04:28 -04002008 break;
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002009 case FORMAT_X32B32G32R32F:
John Bauman89401822014-05-06 15:04:28 -04002010 case FORMAT_A32B32G32R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002011 case FORMAT_A32B32G32R32I:
2012 case FORMAT_A32B32G32R32UI:
John Bauman89401822014-05-06 15:04:28 -04002013 buffer = cBuffer;
John Bauman19bac1e2014-05-06 15:23:49 -04002014 pixel.x = *Pointer<Float4>(buffer + 16 * x, 16);
2015 pixel.y = *Pointer<Float4>(buffer + 16 * x + 16, 16);
Nicolas Capens4f172c72016-01-13 08:34:30 -05002016 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman19bac1e2014-05-06 15:23:49 -04002017 pixel.z = *Pointer<Float4>(buffer + 16 * x, 16);
2018 pixel.w = *Pointer<Float4>(buffer + 16 * x + 16, 16);
2019 transpose4x4(pixel.x, pixel.y, pixel.z, pixel.w);
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002020 if(state.targetFormat[index] == FORMAT_X32B32G32R32F)
2021 {
2022 pixel.w = Float4(1.0f);
2023 }
John Bauman89401822014-05-06 15:04:28 -04002024 break;
2025 default:
2026 ASSERT(false);
2027 }
2028
2029 if(postBlendSRGB && state.writeSRGB)
2030 {
John Bauman19bac1e2014-05-06 15:23:49 -04002031 sRGBtoLinear(pixel.x);
2032 sRGBtoLinear(pixel.y);
2033 sRGBtoLinear(pixel.z);
John Bauman89401822014-05-06 15:04:28 -04002034 }
2035
2036 // Final Color = ObjectColor * SourceBlendFactor + PixelColor * DestinationBlendFactor
John Bauman19bac1e2014-05-06 15:23:49 -04002037 Vector4f sourceFactor;
2038 Vector4f destFactor;
John Bauman89401822014-05-06 15:04:28 -04002039
Nicolas Capens4f172c72016-01-13 08:34:30 -05002040 blendFactor(sourceFactor, oC, pixel, state.sourceBlendFactor);
2041 blendFactor(destFactor, oC, pixel, state.destBlendFactor);
John Bauman89401822014-05-06 15:04:28 -04002042
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002043 if(state.sourceBlendFactor != BLEND_ONE && state.sourceBlendFactor != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04002044 {
John Bauman19bac1e2014-05-06 15:23:49 -04002045 oC.x *= sourceFactor.x;
2046 oC.y *= sourceFactor.y;
2047 oC.z *= sourceFactor.z;
John Bauman89401822014-05-06 15:04:28 -04002048 }
Nicolas Capens05b3d662016-02-25 23:58:33 -05002049
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002050 if(state.destBlendFactor != BLEND_ONE && state.destBlendFactor != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04002051 {
John Bauman19bac1e2014-05-06 15:23:49 -04002052 pixel.x *= destFactor.x;
2053 pixel.y *= destFactor.y;
2054 pixel.z *= destFactor.z;
John Bauman89401822014-05-06 15:04:28 -04002055 }
2056
2057 switch(state.blendOperation)
2058 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002059 case BLENDOP_ADD:
John Bauman19bac1e2014-05-06 15:23:49 -04002060 oC.x += pixel.x;
2061 oC.y += pixel.y;
2062 oC.z += pixel.z;
John Bauman89401822014-05-06 15:04:28 -04002063 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002064 case BLENDOP_SUB:
John Bauman19bac1e2014-05-06 15:23:49 -04002065 oC.x -= pixel.x;
2066 oC.y -= pixel.y;
2067 oC.z -= pixel.z;
John Bauman89401822014-05-06 15:04:28 -04002068 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002069 case BLENDOP_INVSUB:
John Bauman19bac1e2014-05-06 15:23:49 -04002070 oC.x = pixel.x - oC.x;
2071 oC.y = pixel.y - oC.y;
2072 oC.z = pixel.z - oC.z;
John Bauman89401822014-05-06 15:04:28 -04002073 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002074 case BLENDOP_MIN:
John Bauman19bac1e2014-05-06 15:23:49 -04002075 oC.x = Min(oC.x, pixel.x);
2076 oC.y = Min(oC.y, pixel.y);
2077 oC.z = Min(oC.z, pixel.z);
John Bauman89401822014-05-06 15:04:28 -04002078 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002079 case BLENDOP_MAX:
John Bauman19bac1e2014-05-06 15:23:49 -04002080 oC.x = Max(oC.x, pixel.x);
2081 oC.y = Max(oC.y, pixel.y);
2082 oC.z = Max(oC.z, pixel.z);
John Bauman89401822014-05-06 15:04:28 -04002083 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002084 case BLENDOP_SOURCE:
John Bauman89401822014-05-06 15:04:28 -04002085 // No operation
2086 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002087 case BLENDOP_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -04002088 oC.x = pixel.x;
2089 oC.y = pixel.y;
2090 oC.z = pixel.z;
John Bauman89401822014-05-06 15:04:28 -04002091 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002092 case BLENDOP_NULL:
John Bauman19bac1e2014-05-06 15:23:49 -04002093 oC.x = Float4(0.0f);
2094 oC.y = Float4(0.0f);
2095 oC.z = Float4(0.0f);
John Bauman89401822014-05-06 15:04:28 -04002096 break;
2097 default:
2098 ASSERT(false);
2099 }
2100
Nicolas Capens4f172c72016-01-13 08:34:30 -05002101 blendFactorAlpha(sourceFactor, oC, pixel, state.sourceBlendFactorAlpha);
2102 blendFactorAlpha(destFactor, oC, pixel, state.destBlendFactorAlpha);
John Bauman89401822014-05-06 15:04:28 -04002103
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002104 if(state.sourceBlendFactorAlpha != BLEND_ONE && state.sourceBlendFactorAlpha != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04002105 {
John Bauman19bac1e2014-05-06 15:23:49 -04002106 oC.w *= sourceFactor.w;
John Bauman89401822014-05-06 15:04:28 -04002107 }
Nicolas Capens05b3d662016-02-25 23:58:33 -05002108
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002109 if(state.destBlendFactorAlpha != BLEND_ONE && state.destBlendFactorAlpha != BLEND_ZERO)
John Bauman89401822014-05-06 15:04:28 -04002110 {
John Bauman19bac1e2014-05-06 15:23:49 -04002111 pixel.w *= destFactor.w;
John Bauman89401822014-05-06 15:04:28 -04002112 }
2113
2114 switch(state.blendOperationAlpha)
2115 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002116 case BLENDOP_ADD:
John Bauman19bac1e2014-05-06 15:23:49 -04002117 oC.w += pixel.w;
John Bauman89401822014-05-06 15:04:28 -04002118 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002119 case BLENDOP_SUB:
John Bauman19bac1e2014-05-06 15:23:49 -04002120 oC.w -= pixel.w;
John Bauman89401822014-05-06 15:04:28 -04002121 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002122 case BLENDOP_INVSUB:
John Bauman19bac1e2014-05-06 15:23:49 -04002123 pixel.w -= oC.w;
2124 oC.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -04002125 break;
Nicolas Capens05b3d662016-02-25 23:58:33 -05002126 case BLENDOP_MIN:
John Bauman19bac1e2014-05-06 15:23:49 -04002127 oC.w = Min(oC.w, pixel.w);
John Bauman89401822014-05-06 15:04:28 -04002128 break;
Nicolas Capens05b3d662016-02-25 23:58:33 -05002129 case BLENDOP_MAX:
John Bauman19bac1e2014-05-06 15:23:49 -04002130 oC.w = Max(oC.w, pixel.w);
John Bauman89401822014-05-06 15:04:28 -04002131 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002132 case BLENDOP_SOURCE:
John Bauman89401822014-05-06 15:04:28 -04002133 // No operation
2134 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002135 case BLENDOP_DEST:
John Bauman19bac1e2014-05-06 15:23:49 -04002136 oC.w = pixel.w;
John Bauman89401822014-05-06 15:04:28 -04002137 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002138 case BLENDOP_NULL:
John Bauman19bac1e2014-05-06 15:23:49 -04002139 oC.w = Float4(0.0f);
John Bauman89401822014-05-06 15:04:28 -04002140 break;
2141 default:
2142 ASSERT(false);
2143 }
2144 }
2145
Nicolas Capens4f172c72016-01-13 08:34:30 -05002146 void PixelRoutine::writeColor(int index, Pointer<Byte> &cBuffer, Int &x, Vector4f &oC, Int &sMask, Int &zMask, Int &cMask)
John Bauman89401822014-05-06 15:04:28 -04002147 {
John Bauman89401822014-05-06 15:04:28 -04002148 switch(state.targetFormat[index])
2149 {
John Bauman89401822014-05-06 15:04:28 -04002150 case FORMAT_R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002151 case FORMAT_R32I:
2152 case FORMAT_R32UI:
John Bauman89401822014-05-06 15:04:28 -04002153 break;
2154 case FORMAT_G32R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002155 case FORMAT_G32R32I:
2156 case FORMAT_G32R32UI:
John Bauman19bac1e2014-05-06 15:23:49 -04002157 oC.z = oC.x;
2158 oC.x = UnpackLow(oC.x, oC.y);
2159 oC.z = UnpackHigh(oC.z, oC.y);
2160 oC.y = oC.z;
John Bauman89401822014-05-06 15:04:28 -04002161 break;
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002162 case FORMAT_X32B32G32R32F:
John Bauman89401822014-05-06 15:04:28 -04002163 case FORMAT_A32B32G32R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002164 case FORMAT_A32B32G32R32I:
2165 case FORMAT_A32B32G32R32UI:
John Bauman19bac1e2014-05-06 15:23:49 -04002166 transpose4x4(oC.x, oC.y, oC.z, oC.w);
John Bauman89401822014-05-06 15:04:28 -04002167 break;
2168 default:
2169 ASSERT(false);
2170 }
2171
2172 int rgbaWriteMask = state.colorWriteActive(index);
2173
2174 Int xMask; // Combination of all masks
2175
2176 if(state.depthTestActive)
2177 {
2178 xMask = zMask;
2179 }
2180 else
2181 {
2182 xMask = cMask;
2183 }
2184
2185 if(state.stencilActive)
2186 {
2187 xMask &= sMask;
2188 }
2189
2190 Pointer<Byte> buffer;
2191 Float4 value;
2192
2193 switch(state.targetFormat[index])
2194 {
2195 case FORMAT_R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002196 case FORMAT_R32I:
2197 case FORMAT_R32UI:
John Bauman89401822014-05-06 15:04:28 -04002198 if(rgbaWriteMask & 0x00000001)
2199 {
2200 buffer = cBuffer + 4 * x;
2201
2202 // FIXME: movlps
2203 value.x = *Pointer<Float>(buffer + 0);
2204 value.y = *Pointer<Float>(buffer + 4);
2205
Nicolas Capens4f172c72016-01-13 08:34:30 -05002206 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04002207
2208 // FIXME: movhps
2209 value.z = *Pointer<Float>(buffer + 0);
2210 value.w = *Pointer<Float>(buffer + 4);
2211
Nicolas Capens4f172c72016-01-13 08:34:30 -05002212 oC.x = As<Float4>(As<Int4>(oC.x) & *Pointer<Int4>(constants + OFFSET(Constants,maskD4X) + xMask * 16, 16));
2213 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD4X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002214 oC.x = As<Float4>(As<Int4>(oC.x) | As<Int4>(value));
John Bauman89401822014-05-06 15:04:28 -04002215
2216 // FIXME: movhps
John Bauman19bac1e2014-05-06 15:23:49 -04002217 *Pointer<Float>(buffer + 0) = oC.x.z;
2218 *Pointer<Float>(buffer + 4) = oC.x.w;
John Bauman89401822014-05-06 15:04:28 -04002219
Nicolas Capens4f172c72016-01-13 08:34:30 -05002220 buffer -= *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04002221
2222 // FIXME: movlps
John Bauman19bac1e2014-05-06 15:23:49 -04002223 *Pointer<Float>(buffer + 0) = oC.x.x;
2224 *Pointer<Float>(buffer + 4) = oC.x.y;
John Bauman89401822014-05-06 15:04:28 -04002225 }
2226 break;
2227 case FORMAT_G32R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002228 case FORMAT_G32R32I:
2229 case FORMAT_G32R32UI:
John Bauman89401822014-05-06 15:04:28 -04002230 buffer = cBuffer + 8 * x;
2231
2232 value = *Pointer<Float4>(buffer);
2233
2234 if((rgbaWriteMask & 0x00000003) != 0x00000003)
2235 {
2236 Float4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05002237 oC.x = As<Float4>(As<Int4>(oC.x) & *Pointer<Int4>(constants + OFFSET(Constants,maskD01X[rgbaWriteMask & 0x3][0])));
2238 masked = As<Float4>(As<Int4>(masked) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD01X[rgbaWriteMask & 0x3][0])));
John Bauman19bac1e2014-05-06 15:23:49 -04002239 oC.x = As<Float4>(As<Int4>(oC.x) | As<Int4>(masked));
John Bauman89401822014-05-06 15:04:28 -04002240 }
2241
Nicolas Capens4f172c72016-01-13 08:34:30 -05002242 oC.x = As<Float4>(As<Int4>(oC.x) & *Pointer<Int4>(constants + OFFSET(Constants,maskQ01X) + xMask * 16, 16));
2243 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskQ01X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002244 oC.x = As<Float4>(As<Int4>(oC.x) | As<Int4>(value));
2245 *Pointer<Float4>(buffer) = oC.x;
John Bauman89401822014-05-06 15:04:28 -04002246
Nicolas Capens4f172c72016-01-13 08:34:30 -05002247 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04002248
2249 value = *Pointer<Float4>(buffer);
2250
2251 if((rgbaWriteMask & 0x00000003) != 0x00000003)
2252 {
2253 Float4 masked;
2254
2255 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05002256 oC.y = As<Float4>(As<Int4>(oC.y) & *Pointer<Int4>(constants + OFFSET(Constants,maskD01X[rgbaWriteMask & 0x3][0])));
2257 masked = As<Float4>(As<Int4>(masked) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD01X[rgbaWriteMask & 0x3][0])));
John Bauman19bac1e2014-05-06 15:23:49 -04002258 oC.y = As<Float4>(As<Int4>(oC.y) | As<Int4>(masked));
John Bauman89401822014-05-06 15:04:28 -04002259 }
2260
Nicolas Capens4f172c72016-01-13 08:34:30 -05002261 oC.y = As<Float4>(As<Int4>(oC.y) & *Pointer<Int4>(constants + OFFSET(Constants,maskQ23X) + xMask * 16, 16));
2262 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskQ23X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002263 oC.y = As<Float4>(As<Int4>(oC.y) | As<Int4>(value));
2264 *Pointer<Float4>(buffer) = oC.y;
John Bauman89401822014-05-06 15:04:28 -04002265 break;
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002266 case FORMAT_X32B32G32R32F:
John Bauman89401822014-05-06 15:04:28 -04002267 case FORMAT_A32B32G32R32F:
Alexis Hetu1abb6382016-02-08 11:21:16 -05002268 case FORMAT_A32B32G32R32I:
2269 case FORMAT_A32B32G32R32UI:
John Bauman89401822014-05-06 15:04:28 -04002270 buffer = cBuffer + 16 * x;
2271
2272 {
2273 value = *Pointer<Float4>(buffer, 16);
2274
2275 if(rgbaWriteMask != 0x0000000F)
2276 {
2277 Float4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05002278 oC.x = As<Float4>(As<Int4>(oC.x) & *Pointer<Int4>(constants + OFFSET(Constants,maskD4X[rgbaWriteMask][0])));
2279 masked = As<Float4>(As<Int4>(masked) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD4X[rgbaWriteMask][0])));
John Bauman19bac1e2014-05-06 15:23:49 -04002280 oC.x = As<Float4>(As<Int4>(oC.x) | As<Int4>(masked));
John Bauman89401822014-05-06 15:04:28 -04002281 }
Nicolas Capens05b3d662016-02-25 23:58:33 -05002282
Nicolas Capens4f172c72016-01-13 08:34:30 -05002283 oC.x = As<Float4>(As<Int4>(oC.x) & *Pointer<Int4>(constants + OFFSET(Constants,maskX0X) + xMask * 16, 16));
2284 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskX0X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002285 oC.x = As<Float4>(As<Int4>(oC.x) | As<Int4>(value));
2286 *Pointer<Float4>(buffer, 16) = oC.x;
John Bauman89401822014-05-06 15:04:28 -04002287 }
2288
2289 {
2290 value = *Pointer<Float4>(buffer + 16, 16);
2291
2292 if(rgbaWriteMask != 0x0000000F)
Nicolas Capens05b3d662016-02-25 23:58:33 -05002293 {
John Bauman89401822014-05-06 15:04:28 -04002294 Float4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05002295 oC.y = As<Float4>(As<Int4>(oC.y) & *Pointer<Int4>(constants + OFFSET(Constants,maskD4X[rgbaWriteMask][0])));
2296 masked = As<Float4>(As<Int4>(masked) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD4X[rgbaWriteMask][0])));
John Bauman19bac1e2014-05-06 15:23:49 -04002297 oC.y = As<Float4>(As<Int4>(oC.y) | As<Int4>(masked));
John Bauman89401822014-05-06 15:04:28 -04002298 }
2299
Nicolas Capens4f172c72016-01-13 08:34:30 -05002300 oC.y = As<Float4>(As<Int4>(oC.y) & *Pointer<Int4>(constants + OFFSET(Constants,maskX1X) + xMask * 16, 16));
2301 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskX1X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002302 oC.y = As<Float4>(As<Int4>(oC.y) | As<Int4>(value));
2303 *Pointer<Float4>(buffer + 16, 16) = oC.y;
John Bauman89401822014-05-06 15:04:28 -04002304 }
2305
Nicolas Capens4f172c72016-01-13 08:34:30 -05002306 buffer += *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
John Bauman89401822014-05-06 15:04:28 -04002307
2308 {
2309 value = *Pointer<Float4>(buffer, 16);
2310
2311 if(rgbaWriteMask != 0x0000000F)
2312 {
2313 Float4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05002314 oC.z = As<Float4>(As<Int4>(oC.z) & *Pointer<Int4>(constants + OFFSET(Constants,maskD4X[rgbaWriteMask][0])));
2315 masked = As<Float4>(As<Int4>(masked) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD4X[rgbaWriteMask][0])));
John Bauman19bac1e2014-05-06 15:23:49 -04002316 oC.z = As<Float4>(As<Int4>(oC.z) | As<Int4>(masked));
John Bauman89401822014-05-06 15:04:28 -04002317 }
2318
Nicolas Capens4f172c72016-01-13 08:34:30 -05002319 oC.z = As<Float4>(As<Int4>(oC.z) & *Pointer<Int4>(constants + OFFSET(Constants,maskX2X) + xMask * 16, 16));
2320 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskX2X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002321 oC.z = As<Float4>(As<Int4>(oC.z) | As<Int4>(value));
2322 *Pointer<Float4>(buffer, 16) = oC.z;
John Bauman89401822014-05-06 15:04:28 -04002323 }
2324
2325 {
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002326 value = (state.targetFormat[index] == FORMAT_X32B32G32R32F) ? Float4(1.0f) : *Pointer<Float4>(buffer + 16, 16);
John Bauman89401822014-05-06 15:04:28 -04002327
2328 if(rgbaWriteMask != 0x0000000F)
2329 {
2330 Float4 masked = value;
Nicolas Capens4f172c72016-01-13 08:34:30 -05002331 oC.w = As<Float4>(As<Int4>(oC.w) & *Pointer<Int4>(constants + OFFSET(Constants,maskD4X[rgbaWriteMask][0])));
2332 masked = As<Float4>(As<Int4>(masked) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskD4X[rgbaWriteMask][0])));
John Bauman19bac1e2014-05-06 15:23:49 -04002333 oC.w = As<Float4>(As<Int4>(oC.w) | As<Int4>(masked));
John Bauman89401822014-05-06 15:04:28 -04002334 }
2335
Nicolas Capens4f172c72016-01-13 08:34:30 -05002336 oC.w = As<Float4>(As<Int4>(oC.w) & *Pointer<Int4>(constants + OFFSET(Constants,maskX3X) + xMask * 16, 16));
2337 value = As<Float4>(As<Int4>(value) & *Pointer<Int4>(constants + OFFSET(Constants,invMaskX3X) + xMask * 16, 16));
John Bauman19bac1e2014-05-06 15:23:49 -04002338 oC.w = As<Float4>(As<Int4>(oC.w) | As<Int4>(value));
2339 *Pointer<Float4>(buffer + 16, 16) = oC.w;
John Bauman89401822014-05-06 15:04:28 -04002340 }
2341 break;
2342 default:
2343 ASSERT(false);
2344 }
2345 }
2346
John Bauman89401822014-05-06 15:04:28 -04002347 UShort4 PixelRoutine::convertFixed16(Float4 &cf, bool saturate)
2348 {
John Bauman19bac1e2014-05-06 15:23:49 -04002349 return UShort4(cf * Float4(0xFFFF), saturate);
John Bauman89401822014-05-06 15:04:28 -04002350 }
2351
Nicolas Capens4f172c72016-01-13 08:34:30 -05002352 void PixelRoutine::sRGBtoLinear16_12_16(Vector4s &c)
John Bauman89401822014-05-06 15:04:28 -04002353 {
John Bauman19bac1e2014-05-06 15:23:49 -04002354 c.x = As<UShort4>(c.x) >> 4;
2355 c.y = As<UShort4>(c.y) >> 4;
2356 c.z = As<UShort4>(c.z) >> 4;
John Bauman89401822014-05-06 15:04:28 -04002357
Nicolas Capens4f172c72016-01-13 08:34:30 -05002358 sRGBtoLinear12_16(c);
John Bauman89401822014-05-06 15:04:28 -04002359 }
2360
Nicolas Capens4f172c72016-01-13 08:34:30 -05002361 void PixelRoutine::sRGBtoLinear12_16(Vector4s &c)
John Bauman89401822014-05-06 15:04:28 -04002362 {
Nicolas Capens4f172c72016-01-13 08:34:30 -05002363 Pointer<Byte> LUT = constants + OFFSET(Constants,sRGBtoLinear12_16);
John Bauman89401822014-05-06 15:04:28 -04002364
John Bauman19bac1e2014-05-06 15:23:49 -04002365 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 0))), 0);
2366 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 1))), 1);
2367 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 2))), 2);
2368 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 3))), 3);
John Bauman89401822014-05-06 15:04:28 -04002369
John Bauman19bac1e2014-05-06 15:23:49 -04002370 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 0))), 0);
2371 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 1))), 1);
2372 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 2))), 2);
2373 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 3))), 3);
John Bauman89401822014-05-06 15:04:28 -04002374
John Bauman19bac1e2014-05-06 15:23:49 -04002375 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 0))), 0);
2376 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 1))), 1);
2377 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 2))), 2);
2378 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 3))), 3);
John Bauman89401822014-05-06 15:04:28 -04002379 }
2380
Nicolas Capens4f172c72016-01-13 08:34:30 -05002381 void PixelRoutine::linearToSRGB16_12_16(Vector4s &c)
John Bauman89401822014-05-06 15:04:28 -04002382 {
John Bauman19bac1e2014-05-06 15:23:49 -04002383 c.x = As<UShort4>(c.x) >> 4;
2384 c.y = As<UShort4>(c.y) >> 4;
2385 c.z = As<UShort4>(c.z) >> 4;
John Bauman89401822014-05-06 15:04:28 -04002386
Nicolas Capens4f172c72016-01-13 08:34:30 -05002387 linearToSRGB12_16(c);
John Bauman89401822014-05-06 15:04:28 -04002388 }
2389
Nicolas Capens4f172c72016-01-13 08:34:30 -05002390 void PixelRoutine::linearToSRGB12_16(Vector4s &c)
John Bauman89401822014-05-06 15:04:28 -04002391 {
Nicolas Capens4f172c72016-01-13 08:34:30 -05002392 Pointer<Byte> LUT = constants + OFFSET(Constants,linearToSRGB12_16);
John Bauman89401822014-05-06 15:04:28 -04002393
John Bauman19bac1e2014-05-06 15:23:49 -04002394 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 0))), 0);
2395 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 1))), 1);
2396 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 2))), 2);
2397 c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 3))), 3);
John Bauman89401822014-05-06 15:04:28 -04002398
John Bauman19bac1e2014-05-06 15:23:49 -04002399 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 0))), 0);
2400 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 1))), 1);
2401 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 2))), 2);
2402 c.y = Insert(c.y, *Pointer<Short>(LUT + 2 * Int(Extract(c.y, 3))), 3);
John Bauman89401822014-05-06 15:04:28 -04002403
John Bauman19bac1e2014-05-06 15:23:49 -04002404 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 0))), 0);
2405 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 1))), 1);
2406 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 2))), 2);
2407 c.z = Insert(c.z, *Pointer<Short>(LUT + 2 * Int(Extract(c.z, 3))), 3);
John Bauman89401822014-05-06 15:04:28 -04002408 }
2409
John Bauman89401822014-05-06 15:04:28 -04002410 Float4 PixelRoutine::sRGBtoLinear(const Float4 &x) // Approximates x^2.2
2411 {
2412 Float4 linear = x * x;
2413 linear = linear * Float4(0.73f) + linear * x * Float4(0.27f);
2414
2415 return Min(Max(linear, Float4(0.0f)), Float4(1.0f));
2416 }
2417
John Bauman19bac1e2014-05-06 15:23:49 -04002418 bool PixelRoutine::colorUsed()
2419 {
2420 return state.colorWriteMask || state.alphaTestActive() || state.shaderContainsKill;
2421 }
John Bauman89401822014-05-06 15:04:28 -04002422}