1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "QuadRasterizer.hpp"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #include "Primitive.hpp"
18*03ce13f7SAndroid Build Coastguard Worker #include "Renderer.hpp"
19*03ce13f7SAndroid Build Coastguard Worker #include "Pipeline/Constants.hpp"
20*03ce13f7SAndroid Build Coastguard Worker #include "System/Debug.hpp"
21*03ce13f7SAndroid Build Coastguard Worker #include "System/Math.hpp"
22*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkDevice.hpp"
23*03ce13f7SAndroid Build Coastguard Worker
24*03ce13f7SAndroid Build Coastguard Worker namespace sw {
25*03ce13f7SAndroid Build Coastguard Worker
QuadRasterizer(const PixelProcessor::State & state,const SpirvShader * spirvShader)26*03ce13f7SAndroid Build Coastguard Worker QuadRasterizer::QuadRasterizer(const PixelProcessor::State &state, const SpirvShader *spirvShader)
27*03ce13f7SAndroid Build Coastguard Worker : state(state)
28*03ce13f7SAndroid Build Coastguard Worker , spirvShader{ spirvShader }
29*03ce13f7SAndroid Build Coastguard Worker {
30*03ce13f7SAndroid Build Coastguard Worker }
31*03ce13f7SAndroid Build Coastguard Worker
~QuadRasterizer()32*03ce13f7SAndroid Build Coastguard Worker QuadRasterizer::~QuadRasterizer()
33*03ce13f7SAndroid Build Coastguard Worker {
34*03ce13f7SAndroid Build Coastguard Worker }
35*03ce13f7SAndroid Build Coastguard Worker
generate()36*03ce13f7SAndroid Build Coastguard Worker void QuadRasterizer::generate()
37*03ce13f7SAndroid Build Coastguard Worker {
38*03ce13f7SAndroid Build Coastguard Worker constants = device + OFFSET(vk::Device, constants);
39*03ce13f7SAndroid Build Coastguard Worker occlusion = 0;
40*03ce13f7SAndroid Build Coastguard Worker
41*03ce13f7SAndroid Build Coastguard Worker Do
42*03ce13f7SAndroid Build Coastguard Worker {
43*03ce13f7SAndroid Build Coastguard Worker Int yMin = *Pointer<Int>(primitive + OFFSET(Primitive, yMin));
44*03ce13f7SAndroid Build Coastguard Worker Int yMax = *Pointer<Int>(primitive + OFFSET(Primitive, yMax));
45*03ce13f7SAndroid Build Coastguard Worker
46*03ce13f7SAndroid Build Coastguard Worker Int cluster2 = cluster + cluster;
47*03ce13f7SAndroid Build Coastguard Worker yMin += clusterCount * 2 - 2 - cluster2;
48*03ce13f7SAndroid Build Coastguard Worker yMin &= -clusterCount * 2;
49*03ce13f7SAndroid Build Coastguard Worker yMin += cluster2;
50*03ce13f7SAndroid Build Coastguard Worker
51*03ce13f7SAndroid Build Coastguard Worker If(yMin < yMax)
52*03ce13f7SAndroid Build Coastguard Worker {
53*03ce13f7SAndroid Build Coastguard Worker rasterize(yMin, yMax);
54*03ce13f7SAndroid Build Coastguard Worker }
55*03ce13f7SAndroid Build Coastguard Worker
56*03ce13f7SAndroid Build Coastguard Worker primitive += sizeof(Primitive) * state.multiSampleCount;
57*03ce13f7SAndroid Build Coastguard Worker count--;
58*03ce13f7SAndroid Build Coastguard Worker }
59*03ce13f7SAndroid Build Coastguard Worker Until(count == 0);
60*03ce13f7SAndroid Build Coastguard Worker
61*03ce13f7SAndroid Build Coastguard Worker if(state.occlusionEnabled)
62*03ce13f7SAndroid Build Coastguard Worker {
63*03ce13f7SAndroid Build Coastguard Worker UInt clusterOcclusion = *Pointer<UInt>(data + OFFSET(DrawData, occlusion) + 4 * cluster);
64*03ce13f7SAndroid Build Coastguard Worker clusterOcclusion += occlusion;
65*03ce13f7SAndroid Build Coastguard Worker *Pointer<UInt>(data + OFFSET(DrawData, occlusion) + 4 * cluster) = clusterOcclusion;
66*03ce13f7SAndroid Build Coastguard Worker }
67*03ce13f7SAndroid Build Coastguard Worker
68*03ce13f7SAndroid Build Coastguard Worker Return();
69*03ce13f7SAndroid Build Coastguard Worker }
70*03ce13f7SAndroid Build Coastguard Worker
rasterize(Int & yMin,Int & yMax)71*03ce13f7SAndroid Build Coastguard Worker void QuadRasterizer::rasterize(Int &yMin, Int &yMax)
72*03ce13f7SAndroid Build Coastguard Worker {
73*03ce13f7SAndroid Build Coastguard Worker Pointer<Byte> cBuffer[MAX_COLOR_BUFFERS];
74*03ce13f7SAndroid Build Coastguard Worker Pointer<Byte> zBuffer;
75*03ce13f7SAndroid Build Coastguard Worker Pointer<Byte> sBuffer;
76*03ce13f7SAndroid Build Coastguard Worker
77*03ce13f7SAndroid Build Coastguard Worker Int clusterCountLog2 = 31 - Ctlz(UInt(clusterCount), false);
78*03ce13f7SAndroid Build Coastguard Worker
79*03ce13f7SAndroid Build Coastguard Worker for(int index = 0; index < MAX_COLOR_BUFFERS; index++)
80*03ce13f7SAndroid Build Coastguard Worker {
81*03ce13f7SAndroid Build Coastguard Worker if(state.colorWriteActive(index))
82*03ce13f7SAndroid Build Coastguard Worker {
83*03ce13f7SAndroid Build Coastguard Worker cBuffer[index] = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData, colorBuffer[index])) + yMin * *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
84*03ce13f7SAndroid Build Coastguard Worker }
85*03ce13f7SAndroid Build Coastguard Worker }
86*03ce13f7SAndroid Build Coastguard Worker
87*03ce13f7SAndroid Build Coastguard Worker if(state.depthTestActive || state.depthBoundsTestActive)
88*03ce13f7SAndroid Build Coastguard Worker {
89*03ce13f7SAndroid Build Coastguard Worker zBuffer = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData, depthBuffer)) + yMin * *Pointer<Int>(data + OFFSET(DrawData, depthPitchB));
90*03ce13f7SAndroid Build Coastguard Worker }
91*03ce13f7SAndroid Build Coastguard Worker
92*03ce13f7SAndroid Build Coastguard Worker if(state.stencilActive)
93*03ce13f7SAndroid Build Coastguard Worker {
94*03ce13f7SAndroid Build Coastguard Worker sBuffer = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData, stencilBuffer)) + yMin * *Pointer<Int>(data + OFFSET(DrawData, stencilPitchB));
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker
97*03ce13f7SAndroid Build Coastguard Worker Int y = yMin;
98*03ce13f7SAndroid Build Coastguard Worker
99*03ce13f7SAndroid Build Coastguard Worker Do
100*03ce13f7SAndroid Build Coastguard Worker {
101*03ce13f7SAndroid Build Coastguard Worker Int x0a = Int(*Pointer<Short>(primitive + OFFSET(Primitive, outline->left) + (y + 0) * sizeof(Primitive::Span)));
102*03ce13f7SAndroid Build Coastguard Worker Int x0b = Int(*Pointer<Short>(primitive + OFFSET(Primitive, outline->left) + (y + 1) * sizeof(Primitive::Span)));
103*03ce13f7SAndroid Build Coastguard Worker Int x0 = Min(x0a, x0b);
104*03ce13f7SAndroid Build Coastguard Worker
105*03ce13f7SAndroid Build Coastguard Worker for(unsigned int q = 1; q < state.multiSampleCount; q++)
106*03ce13f7SAndroid Build Coastguard Worker {
107*03ce13f7SAndroid Build Coastguard Worker x0a = Int(*Pointer<Short>(primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->left) + (y + 0) * sizeof(Primitive::Span)));
108*03ce13f7SAndroid Build Coastguard Worker x0b = Int(*Pointer<Short>(primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->left) + (y + 1) * sizeof(Primitive::Span)));
109*03ce13f7SAndroid Build Coastguard Worker x0 = Min(x0, Min(x0a, x0b));
110*03ce13f7SAndroid Build Coastguard Worker }
111*03ce13f7SAndroid Build Coastguard Worker
112*03ce13f7SAndroid Build Coastguard Worker x0 &= 0xFFFFFFFE;
113*03ce13f7SAndroid Build Coastguard Worker
114*03ce13f7SAndroid Build Coastguard Worker Int x1a = Int(*Pointer<Short>(primitive + OFFSET(Primitive, outline->right) + (y + 0) * sizeof(Primitive::Span)));
115*03ce13f7SAndroid Build Coastguard Worker Int x1b = Int(*Pointer<Short>(primitive + OFFSET(Primitive, outline->right) + (y + 1) * sizeof(Primitive::Span)));
116*03ce13f7SAndroid Build Coastguard Worker Int x1 = Max(x1a, x1b);
117*03ce13f7SAndroid Build Coastguard Worker
118*03ce13f7SAndroid Build Coastguard Worker for(unsigned int q = 1; q < state.multiSampleCount; q++)
119*03ce13f7SAndroid Build Coastguard Worker {
120*03ce13f7SAndroid Build Coastguard Worker x1a = Int(*Pointer<Short>(primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->right) + (y + 0) * sizeof(Primitive::Span)));
121*03ce13f7SAndroid Build Coastguard Worker x1b = Int(*Pointer<Short>(primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->right) + (y + 1) * sizeof(Primitive::Span)));
122*03ce13f7SAndroid Build Coastguard Worker x1 = Max(x1, Max(x1a, x1b));
123*03ce13f7SAndroid Build Coastguard Worker }
124*03ce13f7SAndroid Build Coastguard Worker
125*03ce13f7SAndroid Build Coastguard Worker // Compute the y coordinate of each fragment in the SIMD group.
126*03ce13f7SAndroid Build Coastguard Worker const auto yMorton = SIMD::Float([](int i) { return float(compactEvenBits(i >> 1)); }); // 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 3, 3, ...
127*03ce13f7SAndroid Build Coastguard Worker yFragment = SIMD::Float(Float(y)) + yMorton - SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, y0)));
128*03ce13f7SAndroid Build Coastguard Worker
129*03ce13f7SAndroid Build Coastguard Worker if(interpolateZ())
130*03ce13f7SAndroid Build Coastguard Worker {
131*03ce13f7SAndroid Build Coastguard Worker for(unsigned int q = 0; q < state.multiSampleCount; q++)
132*03ce13f7SAndroid Build Coastguard Worker {
133*03ce13f7SAndroid Build Coastguard Worker SIMD::Float y = yFragment;
134*03ce13f7SAndroid Build Coastguard Worker
135*03ce13f7SAndroid Build Coastguard Worker if(state.enableMultiSampling)
136*03ce13f7SAndroid Build Coastguard Worker {
137*03ce13f7SAndroid Build Coastguard Worker y += SIMD::Float(*Pointer<Float>(constants + OFFSET(Constants, SampleLocationsY) + q * sizeof(float)));
138*03ce13f7SAndroid Build Coastguard Worker }
139*03ce13f7SAndroid Build Coastguard Worker
140*03ce13f7SAndroid Build Coastguard Worker Dz[q] = SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, z.C))) + y * SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, z.B)));
141*03ce13f7SAndroid Build Coastguard Worker }
142*03ce13f7SAndroid Build Coastguard Worker }
143*03ce13f7SAndroid Build Coastguard Worker
144*03ce13f7SAndroid Build Coastguard Worker If(x0 < x1)
145*03ce13f7SAndroid Build Coastguard Worker {
146*03ce13f7SAndroid Build Coastguard Worker if(interpolateW())
147*03ce13f7SAndroid Build Coastguard Worker {
148*03ce13f7SAndroid Build Coastguard Worker Dw = SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, w.C))) + yFragment * SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, w.B)));
149*03ce13f7SAndroid Build Coastguard Worker }
150*03ce13f7SAndroid Build Coastguard Worker
151*03ce13f7SAndroid Build Coastguard Worker if(spirvShader)
152*03ce13f7SAndroid Build Coastguard Worker {
153*03ce13f7SAndroid Build Coastguard Worker int packedInterpolant = 0;
154*03ce13f7SAndroid Build Coastguard Worker for(int interfaceInterpolant = 0; interfaceInterpolant < MAX_INTERFACE_COMPONENTS; interfaceInterpolant++)
155*03ce13f7SAndroid Build Coastguard Worker {
156*03ce13f7SAndroid Build Coastguard Worker if(spirvShader->inputs[interfaceInterpolant].Type != SpirvShader::ATTRIBTYPE_UNUSED)
157*03ce13f7SAndroid Build Coastguard Worker {
158*03ce13f7SAndroid Build Coastguard Worker Dv[interfaceInterpolant] = *Pointer<Float>(primitive + OFFSET(Primitive, V[packedInterpolant].C));
159*03ce13f7SAndroid Build Coastguard Worker if(!spirvShader->inputs[interfaceInterpolant].Flat)
160*03ce13f7SAndroid Build Coastguard Worker {
161*03ce13f7SAndroid Build Coastguard Worker Dv[interfaceInterpolant] +=
162*03ce13f7SAndroid Build Coastguard Worker yFragment * SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, V[packedInterpolant].B)));
163*03ce13f7SAndroid Build Coastguard Worker }
164*03ce13f7SAndroid Build Coastguard Worker packedInterpolant++;
165*03ce13f7SAndroid Build Coastguard Worker }
166*03ce13f7SAndroid Build Coastguard Worker }
167*03ce13f7SAndroid Build Coastguard Worker
168*03ce13f7SAndroid Build Coastguard Worker for(unsigned int i = 0; i < state.numClipDistances; i++)
169*03ce13f7SAndroid Build Coastguard Worker {
170*03ce13f7SAndroid Build Coastguard Worker DclipDistance[i] = SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, clipDistance[i].C))) +
171*03ce13f7SAndroid Build Coastguard Worker yFragment * SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, clipDistance[i].B)));
172*03ce13f7SAndroid Build Coastguard Worker }
173*03ce13f7SAndroid Build Coastguard Worker
174*03ce13f7SAndroid Build Coastguard Worker for(unsigned int i = 0; i < state.numCullDistances; i++)
175*03ce13f7SAndroid Build Coastguard Worker {
176*03ce13f7SAndroid Build Coastguard Worker DcullDistance[i] = SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, cullDistance[i].C))) +
177*03ce13f7SAndroid Build Coastguard Worker yFragment * SIMD::Float(*Pointer<Float>(primitive + OFFSET(Primitive, cullDistance[i].B)));
178*03ce13f7SAndroid Build Coastguard Worker }
179*03ce13f7SAndroid Build Coastguard Worker }
180*03ce13f7SAndroid Build Coastguard Worker
181*03ce13f7SAndroid Build Coastguard Worker Short4 xLeft[4];
182*03ce13f7SAndroid Build Coastguard Worker Short4 xRight[4];
183*03ce13f7SAndroid Build Coastguard Worker
184*03ce13f7SAndroid Build Coastguard Worker for(unsigned int q = 0; q < state.multiSampleCount; q++)
185*03ce13f7SAndroid Build Coastguard Worker {
186*03ce13f7SAndroid Build Coastguard Worker xLeft[q] = *Pointer<Short4>(primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline) + y * sizeof(Primitive::Span));
187*03ce13f7SAndroid Build Coastguard Worker xRight[q] = xLeft[q];
188*03ce13f7SAndroid Build Coastguard Worker
189*03ce13f7SAndroid Build Coastguard Worker xLeft[q] = Swizzle(xLeft[q], 0x0022) - Short4(1, 2, 1, 2);
190*03ce13f7SAndroid Build Coastguard Worker xRight[q] = Swizzle(xRight[q], 0x1133) - Short4(0, 1, 0, 1);
191*03ce13f7SAndroid Build Coastguard Worker }
192*03ce13f7SAndroid Build Coastguard Worker
193*03ce13f7SAndroid Build Coastguard Worker For(Int x = x0, x < x1, x += 2)
194*03ce13f7SAndroid Build Coastguard Worker {
195*03ce13f7SAndroid Build Coastguard Worker Short4 xxxx = Short4(x);
196*03ce13f7SAndroid Build Coastguard Worker Int cMask[4];
197*03ce13f7SAndroid Build Coastguard Worker
198*03ce13f7SAndroid Build Coastguard Worker for(unsigned int q = 0; q < state.multiSampleCount; q++)
199*03ce13f7SAndroid Build Coastguard Worker {
200*03ce13f7SAndroid Build Coastguard Worker if(state.multiSampleMask & (1 << q))
201*03ce13f7SAndroid Build Coastguard Worker {
202*03ce13f7SAndroid Build Coastguard Worker unsigned int i = state.enableMultiSampling ? q : 0;
203*03ce13f7SAndroid Build Coastguard Worker Short4 mask = CmpGT(xxxx, xLeft[i]) & CmpGT(xRight[i], xxxx);
204*03ce13f7SAndroid Build Coastguard Worker cMask[q] = SignMask(PackSigned(mask, mask)) & 0x0000000F;
205*03ce13f7SAndroid Build Coastguard Worker }
206*03ce13f7SAndroid Build Coastguard Worker }
207*03ce13f7SAndroid Build Coastguard Worker
208*03ce13f7SAndroid Build Coastguard Worker quad(cBuffer, zBuffer, sBuffer, cMask, x, y);
209*03ce13f7SAndroid Build Coastguard Worker }
210*03ce13f7SAndroid Build Coastguard Worker }
211*03ce13f7SAndroid Build Coastguard Worker
212*03ce13f7SAndroid Build Coastguard Worker for(int index = 0; index < MAX_COLOR_BUFFERS; index++)
213*03ce13f7SAndroid Build Coastguard Worker {
214*03ce13f7SAndroid Build Coastguard Worker if(state.colorWriteActive(index))
215*03ce13f7SAndroid Build Coastguard Worker {
216*03ce13f7SAndroid Build Coastguard Worker cBuffer[index] += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index])) << (1 + clusterCountLog2); // FIXME: Precompute
217*03ce13f7SAndroid Build Coastguard Worker }
218*03ce13f7SAndroid Build Coastguard Worker }
219*03ce13f7SAndroid Build Coastguard Worker
220*03ce13f7SAndroid Build Coastguard Worker if(state.depthTestActive || state.depthBoundsTestActive)
221*03ce13f7SAndroid Build Coastguard Worker {
222*03ce13f7SAndroid Build Coastguard Worker zBuffer += *Pointer<Int>(data + OFFSET(DrawData, depthPitchB)) << (1 + clusterCountLog2); // FIXME: Precompute
223*03ce13f7SAndroid Build Coastguard Worker }
224*03ce13f7SAndroid Build Coastguard Worker
225*03ce13f7SAndroid Build Coastguard Worker if(state.stencilActive)
226*03ce13f7SAndroid Build Coastguard Worker {
227*03ce13f7SAndroid Build Coastguard Worker sBuffer += *Pointer<Int>(data + OFFSET(DrawData, stencilPitchB)) << (1 + clusterCountLog2); // FIXME: Precompute
228*03ce13f7SAndroid Build Coastguard Worker }
229*03ce13f7SAndroid Build Coastguard Worker
230*03ce13f7SAndroid Build Coastguard Worker y += 2 * clusterCount;
231*03ce13f7SAndroid Build Coastguard Worker }
232*03ce13f7SAndroid Build Coastguard Worker Until(y >= yMax);
233*03ce13f7SAndroid Build Coastguard Worker }
234*03ce13f7SAndroid Build Coastguard Worker
interpolate(SIMD::Float & x,SIMD::Float & D,SIMD::Float & rhw,Pointer<Byte> planeEquation,bool flat,bool perspective)235*03ce13f7SAndroid Build Coastguard Worker SIMD::Float QuadRasterizer::interpolate(SIMD::Float &x, SIMD::Float &D, SIMD::Float &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective)
236*03ce13f7SAndroid Build Coastguard Worker {
237*03ce13f7SAndroid Build Coastguard Worker if(flat)
238*03ce13f7SAndroid Build Coastguard Worker {
239*03ce13f7SAndroid Build Coastguard Worker return D;
240*03ce13f7SAndroid Build Coastguard Worker }
241*03ce13f7SAndroid Build Coastguard Worker
242*03ce13f7SAndroid Build Coastguard Worker SIMD::Float interpolant = mulAdd(x, SIMD::Float(*Pointer<Float>(planeEquation + OFFSET(PlaneEquation, A))), D);
243*03ce13f7SAndroid Build Coastguard Worker
244*03ce13f7SAndroid Build Coastguard Worker if(perspective)
245*03ce13f7SAndroid Build Coastguard Worker {
246*03ce13f7SAndroid Build Coastguard Worker interpolant *= rhw;
247*03ce13f7SAndroid Build Coastguard Worker }
248*03ce13f7SAndroid Build Coastguard Worker
249*03ce13f7SAndroid Build Coastguard Worker return interpolant;
250*03ce13f7SAndroid Build Coastguard Worker }
251*03ce13f7SAndroid Build Coastguard Worker
interpolateZ() const252*03ce13f7SAndroid Build Coastguard Worker bool QuadRasterizer::interpolateZ() const
253*03ce13f7SAndroid Build Coastguard Worker {
254*03ce13f7SAndroid Build Coastguard Worker return state.depthTestActive || (spirvShader && spirvShader->hasBuiltinInput(spv::BuiltInFragCoord));
255*03ce13f7SAndroid Build Coastguard Worker }
256*03ce13f7SAndroid Build Coastguard Worker
interpolateW() const257*03ce13f7SAndroid Build Coastguard Worker bool QuadRasterizer::interpolateW() const
258*03ce13f7SAndroid Build Coastguard Worker {
259*03ce13f7SAndroid Build Coastguard Worker // Note: could optimize cases where there is a fragment shader but it has no
260*03ce13f7SAndroid Build Coastguard Worker // perspective-correct inputs, but that's vanishingly rare.
261*03ce13f7SAndroid Build Coastguard Worker return spirvShader != nullptr;
262*03ce13f7SAndroid Build Coastguard Worker }
263*03ce13f7SAndroid Build Coastguard Worker
264*03ce13f7SAndroid Build Coastguard Worker } // namespace sw
265