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 "PixelProcessor.hpp"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #include "Primitive.hpp"
18*03ce13f7SAndroid Build Coastguard Worker #include "Pipeline/Constants.hpp"
19*03ce13f7SAndroid Build Coastguard Worker #include "Pipeline/PixelProgram.hpp"
20*03ce13f7SAndroid Build Coastguard Worker #include "System/Debug.hpp"
21*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkImageView.hpp"
22*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkPipelineLayout.hpp"
23*03ce13f7SAndroid Build Coastguard Worker
24*03ce13f7SAndroid Build Coastguard Worker #include <cstring>
25*03ce13f7SAndroid Build Coastguard Worker
26*03ce13f7SAndroid Build Coastguard Worker namespace sw {
27*03ce13f7SAndroid Build Coastguard Worker
computeHash()28*03ce13f7SAndroid Build Coastguard Worker uint32_t PixelProcessor::States::computeHash()
29*03ce13f7SAndroid Build Coastguard Worker {
30*03ce13f7SAndroid Build Coastguard Worker uint32_t *state = reinterpret_cast<uint32_t *>(this);
31*03ce13f7SAndroid Build Coastguard Worker uint32_t hash = 0;
32*03ce13f7SAndroid Build Coastguard Worker
33*03ce13f7SAndroid Build Coastguard Worker for(unsigned int i = 0; i < sizeof(States) / sizeof(uint32_t); i++)
34*03ce13f7SAndroid Build Coastguard Worker {
35*03ce13f7SAndroid Build Coastguard Worker hash ^= state[i];
36*03ce13f7SAndroid Build Coastguard Worker }
37*03ce13f7SAndroid Build Coastguard Worker
38*03ce13f7SAndroid Build Coastguard Worker return hash;
39*03ce13f7SAndroid Build Coastguard Worker }
40*03ce13f7SAndroid Build Coastguard Worker
operator ==(const State & state) const41*03ce13f7SAndroid Build Coastguard Worker bool PixelProcessor::State::operator==(const State &state) const
42*03ce13f7SAndroid Build Coastguard Worker {
43*03ce13f7SAndroid Build Coastguard Worker if(hash != state.hash)
44*03ce13f7SAndroid Build Coastguard Worker {
45*03ce13f7SAndroid Build Coastguard Worker return false;
46*03ce13f7SAndroid Build Coastguard Worker }
47*03ce13f7SAndroid Build Coastguard Worker
48*03ce13f7SAndroid Build Coastguard Worker return *static_cast<const States *>(this) == static_cast<const States &>(state);
49*03ce13f7SAndroid Build Coastguard Worker }
50*03ce13f7SAndroid Build Coastguard Worker
PixelProcessor()51*03ce13f7SAndroid Build Coastguard Worker PixelProcessor::PixelProcessor()
52*03ce13f7SAndroid Build Coastguard Worker {
53*03ce13f7SAndroid Build Coastguard Worker setRoutineCacheSize(1024);
54*03ce13f7SAndroid Build Coastguard Worker }
55*03ce13f7SAndroid Build Coastguard Worker
setBlendConstant(const float4 & blendConstant)56*03ce13f7SAndroid Build Coastguard Worker void PixelProcessor::setBlendConstant(const float4 &blendConstant)
57*03ce13f7SAndroid Build Coastguard Worker {
58*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < 4; i++)
59*03ce13f7SAndroid Build Coastguard Worker {
60*03ce13f7SAndroid Build Coastguard Worker factor.blendConstantF[i] = blendConstant[i];
61*03ce13f7SAndroid Build Coastguard Worker factor.invBlendConstantF[i] = 1.0f - blendConstant[i];
62*03ce13f7SAndroid Build Coastguard Worker factor.blendConstantU[i] = clamp(blendConstant[i], 0.0f, 1.0f);
63*03ce13f7SAndroid Build Coastguard Worker factor.invBlendConstantU[i] = 1.0f - clamp(blendConstant[i], 0.0f, 1.0f);
64*03ce13f7SAndroid Build Coastguard Worker factor.blendConstantS[i] = clamp(blendConstant[i], -1.0f, 1.0f);
65*03ce13f7SAndroid Build Coastguard Worker factor.invBlendConstantS[i] = 1.0f - clamp(blendConstant[i], -1.0f, 1.0f);
66*03ce13f7SAndroid Build Coastguard Worker }
67*03ce13f7SAndroid Build Coastguard Worker }
68*03ce13f7SAndroid Build Coastguard Worker
setRoutineCacheSize(int cacheSize)69*03ce13f7SAndroid Build Coastguard Worker void PixelProcessor::setRoutineCacheSize(int cacheSize)
70*03ce13f7SAndroid Build Coastguard Worker {
71*03ce13f7SAndroid Build Coastguard Worker routineCache = std::make_unique<RoutineCacheType>(clamp(cacheSize, 1, 65536));
72*03ce13f7SAndroid Build Coastguard Worker }
73*03ce13f7SAndroid Build Coastguard Worker
update(const vk::GraphicsState & pipelineState,const sw::SpirvShader * fragmentShader,const sw::SpirvShader * vertexShader,const vk::Attachments & attachments,bool occlusionEnabled) const74*03ce13f7SAndroid Build Coastguard Worker const PixelProcessor::State PixelProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments, bool occlusionEnabled) const
75*03ce13f7SAndroid Build Coastguard Worker {
76*03ce13f7SAndroid Build Coastguard Worker const vk::VertexInputInterfaceState &vertexInputInterfaceState = pipelineState.getVertexInputInterfaceState();
77*03ce13f7SAndroid Build Coastguard Worker const vk::PreRasterizationState &preRasterizationState = pipelineState.getPreRasterizationState();
78*03ce13f7SAndroid Build Coastguard Worker const vk::FragmentState &fragmentState = pipelineState.getFragmentState();
79*03ce13f7SAndroid Build Coastguard Worker const vk::FragmentOutputInterfaceState &fragmentOutputInterfaceState = pipelineState.getFragmentOutputInterfaceState();
80*03ce13f7SAndroid Build Coastguard Worker
81*03ce13f7SAndroid Build Coastguard Worker State state;
82*03ce13f7SAndroid Build Coastguard Worker
83*03ce13f7SAndroid Build Coastguard Worker state.numClipDistances = vertexShader->getNumOutputClipDistances();
84*03ce13f7SAndroid Build Coastguard Worker state.numCullDistances = vertexShader->getNumOutputCullDistances();
85*03ce13f7SAndroid Build Coastguard Worker
86*03ce13f7SAndroid Build Coastguard Worker if(fragmentShader)
87*03ce13f7SAndroid Build Coastguard Worker {
88*03ce13f7SAndroid Build Coastguard Worker state.shaderID = fragmentShader->getIdentifier();
89*03ce13f7SAndroid Build Coastguard Worker state.pipelineLayoutIdentifier = fragmentState.getPipelineLayout()->identifier;
90*03ce13f7SAndroid Build Coastguard Worker state.robustBufferAccess = fragmentShader->getRobustBufferAccess();
91*03ce13f7SAndroid Build Coastguard Worker }
92*03ce13f7SAndroid Build Coastguard Worker else
93*03ce13f7SAndroid Build Coastguard Worker {
94*03ce13f7SAndroid Build Coastguard Worker state.shaderID = 0;
95*03ce13f7SAndroid Build Coastguard Worker state.pipelineLayoutIdentifier = 0;
96*03ce13f7SAndroid Build Coastguard Worker state.robustBufferAccess = false;
97*03ce13f7SAndroid Build Coastguard Worker }
98*03ce13f7SAndroid Build Coastguard Worker
99*03ce13f7SAndroid Build Coastguard Worker state.alphaToCoverage = fragmentOutputInterfaceState.hasAlphaToCoverage();
100*03ce13f7SAndroid Build Coastguard Worker state.depthWriteEnable = fragmentState.depthWriteActive(attachments);
101*03ce13f7SAndroid Build Coastguard Worker
102*03ce13f7SAndroid Build Coastguard Worker if(fragmentState.stencilActive(attachments))
103*03ce13f7SAndroid Build Coastguard Worker {
104*03ce13f7SAndroid Build Coastguard Worker state.stencilActive = true;
105*03ce13f7SAndroid Build Coastguard Worker state.frontStencil = fragmentState.getFrontStencil();
106*03ce13f7SAndroid Build Coastguard Worker state.backStencil = fragmentState.getBackStencil();
107*03ce13f7SAndroid Build Coastguard Worker }
108*03ce13f7SAndroid Build Coastguard Worker
109*03ce13f7SAndroid Build Coastguard Worker state.depthFormat = attachments.depthFormat();
110*03ce13f7SAndroid Build Coastguard Worker state.depthBoundsTestActive = fragmentState.depthBoundsTestActive(attachments);
111*03ce13f7SAndroid Build Coastguard Worker state.minDepthBounds = fragmentState.getMinDepthBounds();
112*03ce13f7SAndroid Build Coastguard Worker state.maxDepthBounds = fragmentState.getMaxDepthBounds();
113*03ce13f7SAndroid Build Coastguard Worker
114*03ce13f7SAndroid Build Coastguard Worker if(fragmentState.depthTestActive(attachments))
115*03ce13f7SAndroid Build Coastguard Worker {
116*03ce13f7SAndroid Build Coastguard Worker state.depthTestActive = true;
117*03ce13f7SAndroid Build Coastguard Worker state.depthCompareMode = fragmentState.getDepthCompareMode();
118*03ce13f7SAndroid Build Coastguard Worker
119*03ce13f7SAndroid Build Coastguard Worker state.depthBias = preRasterizationState.getConstantDepthBias() != 0.0f || preRasterizationState.getSlopeDepthBias() != 0.0f;
120*03ce13f7SAndroid Build Coastguard Worker
121*03ce13f7SAndroid Build Coastguard Worker bool pipelineDepthClamp = preRasterizationState.getDepthClampEnable();
122*03ce13f7SAndroid Build Coastguard Worker // "For fixed-point depth buffers, fragment depth values are always limited to the range [0,1] by clamping after depth bias addition is performed.
123*03ce13f7SAndroid Build Coastguard Worker // Unless the VK_EXT_depth_range_unrestricted extension is enabled, fragment depth values are clamped even when the depth buffer uses a floating-point representation."
124*03ce13f7SAndroid Build Coastguard Worker state.depthClamp = pipelineDepthClamp || !state.depthFormat.isFloatFormat() || !preRasterizationState.hasDepthRangeUnrestricted();
125*03ce13f7SAndroid Build Coastguard Worker
126*03ce13f7SAndroid Build Coastguard Worker if(pipelineDepthClamp)
127*03ce13f7SAndroid Build Coastguard Worker {
128*03ce13f7SAndroid Build Coastguard Worker const VkViewport viewport = preRasterizationState.getViewport();
129*03ce13f7SAndroid Build Coastguard Worker state.minDepthClamp = min(viewport.minDepth, viewport.maxDepth);
130*03ce13f7SAndroid Build Coastguard Worker state.maxDepthClamp = max(viewport.minDepth, viewport.maxDepth);
131*03ce13f7SAndroid Build Coastguard Worker }
132*03ce13f7SAndroid Build Coastguard Worker else if(state.depthClamp)
133*03ce13f7SAndroid Build Coastguard Worker {
134*03ce13f7SAndroid Build Coastguard Worker state.minDepthClamp = 0.0f;
135*03ce13f7SAndroid Build Coastguard Worker state.maxDepthClamp = 1.0f;
136*03ce13f7SAndroid Build Coastguard Worker }
137*03ce13f7SAndroid Build Coastguard Worker }
138*03ce13f7SAndroid Build Coastguard Worker
139*03ce13f7SAndroid Build Coastguard Worker state.occlusionEnabled = occlusionEnabled;
140*03ce13f7SAndroid Build Coastguard Worker
141*03ce13f7SAndroid Build Coastguard Worker bool fragmentContainsDiscard = (fragmentShader && fragmentShader->getAnalysis().ContainsDiscard);
142*03ce13f7SAndroid Build Coastguard Worker for(uint32_t location = 0; location < MAX_COLOR_BUFFERS; location++)
143*03ce13f7SAndroid Build Coastguard Worker {
144*03ce13f7SAndroid Build Coastguard Worker state.colorFormat[location] = attachments.colorFormat(location);
145*03ce13f7SAndroid Build Coastguard Worker
146*03ce13f7SAndroid Build Coastguard Worker state.colorWriteMask |= fragmentOutputInterfaceState.colorWriteActive(location, attachments) << (4 * location);
147*03ce13f7SAndroid Build Coastguard Worker state.blendState[location] = fragmentOutputInterfaceState.getBlendState(location, attachments, fragmentContainsDiscard);
148*03ce13f7SAndroid Build Coastguard Worker }
149*03ce13f7SAndroid Build Coastguard Worker
150*03ce13f7SAndroid Build Coastguard Worker const bool isBresenhamLine = vertexInputInterfaceState.isDrawLine(true, preRasterizationState.getPolygonMode()) &&
151*03ce13f7SAndroid Build Coastguard Worker preRasterizationState.getLineRasterizationMode() == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
152*03ce13f7SAndroid Build Coastguard Worker
153*03ce13f7SAndroid Build Coastguard Worker state.multiSampleCount = static_cast<unsigned int>(fragmentOutputInterfaceState.getSampleCount());
154*03ce13f7SAndroid Build Coastguard Worker state.multiSampleMask = fragmentOutputInterfaceState.getMultiSampleMask();
155*03ce13f7SAndroid Build Coastguard Worker state.enableMultiSampling = state.multiSampleCount > 1 && !isBresenhamLine;
156*03ce13f7SAndroid Build Coastguard Worker
157*03ce13f7SAndroid Build Coastguard Worker // SampleId and SamplePosition require per-sample fragment shader invocations, so the Vulkan spec
158*03ce13f7SAndroid Build Coastguard Worker // requires turning on sample shading if either of them is present in the shader:
159*03ce13f7SAndroid Build Coastguard Worker // "If a fragment shader entry point's interface includes an input variable decorated with SampleId,
160*03ce13f7SAndroid Build Coastguard Worker // Sample Shading is considered enabled with a minSampleShading value of 1.0."
161*03ce13f7SAndroid Build Coastguard Worker // "If a fragment shader entry point's interface includes an input variable decorated with SamplePosition,
162*03ce13f7SAndroid Build Coastguard Worker // Sample Shading is considered enabled with a minSampleShading value of 1.0."
163*03ce13f7SAndroid Build Coastguard Worker bool shaderContainsSampleDecoration = fragmentShader && (fragmentShader->hasBuiltinInput(spv::BuiltInSampleId) ||
164*03ce13f7SAndroid Build Coastguard Worker fragmentShader->hasBuiltinInput(spv::BuiltInSamplePosition));
165*03ce13f7SAndroid Build Coastguard Worker
166*03ce13f7SAndroid Build Coastguard Worker if(shaderContainsSampleDecoration)
167*03ce13f7SAndroid Build Coastguard Worker {
168*03ce13f7SAndroid Build Coastguard Worker state.sampleShadingEnabled = true;
169*03ce13f7SAndroid Build Coastguard Worker state.minSampleShading = 1.0f;
170*03ce13f7SAndroid Build Coastguard Worker }
171*03ce13f7SAndroid Build Coastguard Worker else
172*03ce13f7SAndroid Build Coastguard Worker {
173*03ce13f7SAndroid Build Coastguard Worker state.sampleShadingEnabled = fragmentOutputInterfaceState.hasSampleShadingEnabled();
174*03ce13f7SAndroid Build Coastguard Worker state.minSampleShading = fragmentOutputInterfaceState.getMinSampleShading();
175*03ce13f7SAndroid Build Coastguard Worker }
176*03ce13f7SAndroid Build Coastguard Worker
177*03ce13f7SAndroid Build Coastguard Worker if(state.enableMultiSampling && fragmentShader)
178*03ce13f7SAndroid Build Coastguard Worker {
179*03ce13f7SAndroid Build Coastguard Worker state.centroid = fragmentShader->getAnalysis().NeedsCentroid;
180*03ce13f7SAndroid Build Coastguard Worker }
181*03ce13f7SAndroid Build Coastguard Worker
182*03ce13f7SAndroid Build Coastguard Worker state.frontFace = preRasterizationState.getFrontFace();
183*03ce13f7SAndroid Build Coastguard Worker
184*03ce13f7SAndroid Build Coastguard Worker state.hash = state.computeHash();
185*03ce13f7SAndroid Build Coastguard Worker
186*03ce13f7SAndroid Build Coastguard Worker return state;
187*03ce13f7SAndroid Build Coastguard Worker }
188*03ce13f7SAndroid Build Coastguard Worker
routine(const State & state,const vk::PipelineLayout * pipelineLayout,const SpirvShader * pixelShader,const vk::Attachments & attachments,const vk::DescriptorSet::Bindings & descriptorSets)189*03ce13f7SAndroid Build Coastguard Worker PixelProcessor::RoutineType PixelProcessor::routine(const State &state,
190*03ce13f7SAndroid Build Coastguard Worker const vk::PipelineLayout *pipelineLayout,
191*03ce13f7SAndroid Build Coastguard Worker const SpirvShader *pixelShader,
192*03ce13f7SAndroid Build Coastguard Worker const vk::Attachments &attachments,
193*03ce13f7SAndroid Build Coastguard Worker const vk::DescriptorSet::Bindings &descriptorSets)
194*03ce13f7SAndroid Build Coastguard Worker {
195*03ce13f7SAndroid Build Coastguard Worker auto routine = routineCache->lookup(state);
196*03ce13f7SAndroid Build Coastguard Worker
197*03ce13f7SAndroid Build Coastguard Worker if(!routine)
198*03ce13f7SAndroid Build Coastguard Worker {
199*03ce13f7SAndroid Build Coastguard Worker QuadRasterizer *generator = new PixelProgram(state, pipelineLayout, pixelShader, attachments, descriptorSets);
200*03ce13f7SAndroid Build Coastguard Worker generator->generate();
201*03ce13f7SAndroid Build Coastguard Worker routine = (*generator)("PixelRoutine_%0.8X", state.shaderID);
202*03ce13f7SAndroid Build Coastguard Worker delete generator;
203*03ce13f7SAndroid Build Coastguard Worker
204*03ce13f7SAndroid Build Coastguard Worker routineCache->add(state, routine);
205*03ce13f7SAndroid Build Coastguard Worker }
206*03ce13f7SAndroid Build Coastguard Worker
207*03ce13f7SAndroid Build Coastguard Worker return routine;
208*03ce13f7SAndroid Build Coastguard Worker }
209*03ce13f7SAndroid Build Coastguard Worker
210*03ce13f7SAndroid Build Coastguard Worker } // namespace sw
211