1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "SetupProcessor.hpp"
16
17#include "Primitive.hpp"
18#include "Polygon.hpp"
19#include "Context.hpp"
20#include "Renderer.hpp"
21#include "Shader/SetupRoutine.hpp"
22#include "Shader/Constants.hpp"
23#include "Common/Debug.hpp"
24
25#include <cstring>
26
27namespace sw
28{
29 extern bool complementaryDepthBuffer;
30 extern bool fullPixelPositionRegister;
31
32 bool precacheSetup = false;
33
34 uint32_t SetupProcessor::States::computeHash()
35 {
36 uint32_t *state = reinterpret_cast<uint32_t*>(this);
37 uint32_t hash = 0;
38
39 for(unsigned int i = 0; i < sizeof(States) / sizeof(uint32_t); i++)
40 {
41 hash ^= state[i];
42 }
43
44 return hash;
45 }
46
47 bool SetupProcessor::State::operator==(const State &state) const
48 {
49 if(hash != state.hash)
50 {
51 return false;
52 }
53
54 static_assert(is_memcmparable<State>::value, "Cannot memcmp States");
55 return memcmp(static_cast<const States*>(this), static_cast<const States*>(&state), sizeof(States)) == 0;
56 }
57
58 SetupProcessor::SetupProcessor(Context *context) : context(context)
59 {
60 routineCache = nullptr;
61 setRoutineCacheSize(1024);
62 }
63
64 SetupProcessor::~SetupProcessor()
65 {
66 delete routineCache;
67 routineCache = nullptr;
68 }
69
70 SetupProcessor::State SetupProcessor::update() const
71 {
72 State state;
73
74 bool vPosZW = (context->pixelShader && context->pixelShader->isVPosDeclared() && fullPixelPositionRegister);
75
76 state.isDrawPoint = context->isDrawPoint(true);
77 state.isDrawLine = context->isDrawLine(true);
78 state.isDrawTriangle = context->isDrawTriangle(false);
79 state.isDrawSolidTriangle = context->isDrawTriangle(true);
80 state.interpolateZ = context->depthBufferActive() || context->pixelFogActive() != FOG_NONE || vPosZW;
81 state.interpolateW = context->perspectiveActive() || vPosZW;
82 state.perspective = context->perspectiveActive();
83 state.pointSprite = context->pointSpriteActive();
84 state.cullMode = context->cullMode;
85 state.twoSidedStencil = context->stencilActive() && context->twoSidedStencil;
86 state.slopeDepthBias = context->slopeDepthBias != 0.0f;
87 state.vFace = context->pixelShader && context->pixelShader->isVFaceDeclared();
88
89 state.positionRegister = Pos;
90 state.pointSizeRegister = Unused;
91
92 state.multiSample = context->getMultiSampleCount();
93 state.rasterizerDiscard = context->rasterizerDiscard;
94
95 if(context->vertexShader)
96 {
97 state.positionRegister = context->vertexShader->getPositionRegister();
98 state.pointSizeRegister = context->vertexShader->getPointSizeRegister();
99 }
100 else if(context->pointSizeActive())
101 {
102 state.pointSizeRegister = Pts;
103 }
104
105 for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
106 {
107 for(int component = 0; component < 4; component++)
108 {
109 state.gradient[interpolant][component].attribute = Unused;
110 state.gradient[interpolant][component].flat = false;
111 state.gradient[interpolant][component].wrap = false;
112 }
113 }
114
115 state.fog.attribute = Unused;
116 state.fog.flat = false;
117 state.fog.wrap = false;
118
119 const bool point = context->isDrawPoint(true);
120 const bool sprite = context->pointSpriteActive();
121 const bool flatShading = (context->shadingMode == SHADING_FLAT) || point;
122
123 if(context->vertexShader && context->pixelShader)
124 {
125 for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
126 {
127 for(int component = 0; component < 4; component++)
128 {
129 int project = context->isProjectionComponent(interpolant - 2, component) ? 1 : 0;
130 const Shader::Semantic& semantic = context->pixelShader->getInput(interpolant, component - project);
131
132 if(semantic.active())
133 {
134 int input = interpolant;
135 for(int i = 0; i < MAX_VERTEX_OUTPUTS; i++)
136 {
137 if(semantic == context->vertexShader->getOutput(i, component - project))
138 {
139 input = i;
140 break;
141 }
142 }
143
144 bool flat = point;
145
146 switch(semantic.usage)
147 {
148 case Shader::USAGE_TEXCOORD: flat = point && !sprite; break;
149 case Shader::USAGE_COLOR: flat = semantic.flat || flatShading; break;
150 }
151
152 state.gradient[interpolant][component].attribute = input;
153 state.gradient[interpolant][component].flat = flat;
154 }
155 }
156 }
157 }
158 else if(context->preTransformed && context->pixelShader)
159 {
160 for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
161 {
162 for(int component = 0; component < 4; component++)
163 {
164 const Shader::Semantic& semantic = context->pixelShader->getInput(interpolant, component);
165
166 switch(semantic.usage)
167 {
168 case 0xFF:
169 break;
170 case Shader::USAGE_TEXCOORD:
171 state.gradient[interpolant][component].attribute = T0 + semantic.index;
172 state.gradient[interpolant][component].flat = semantic.flat || (point && !sprite);
173 break;
174 case Shader::USAGE_COLOR:
175 state.gradient[interpolant][component].attribute = C0 + semantic.index;
176 state.gradient[interpolant][component].flat = semantic.flat || flatShading;
177 break;
178 default:
179 ASSERT(false);
180 }
181 }
182 }
183 }
184 else if(context->pixelShaderModel() < 0x0300)
185 {
186 for(int coordinate = 0; coordinate < 8; coordinate++)
187 {
188 for(int component = 0; component < 4; component++)
189 {
190 if(context->textureActive(coordinate, component))
191 {
192 state.texture[coordinate][component].attribute = T0 + coordinate;
193 state.texture[coordinate][component].flat = point && !sprite;
194 state.texture[coordinate][component].wrap = (context->textureWrap[coordinate] & (1 << component)) != 0;
195 }
196 }
197 }
198
199 for(int color = 0; color < 2; color++)
200 {
201 for(int component = 0; component < 4; component++)
202 {
203 if(context->colorActive(color, component))
204 {
205 state.color[color][component].attribute = C0 + color;
206 state.color[color][component].flat = flatShading;
207 }
208 }
209 }
210 }
211 else ASSERT(false);
212
213 if(context->fogActive())
214 {
215 state.fog.attribute = Fog;
216 state.fog.flat = point;
217 }
218
219 state.hash = state.computeHash();
220
221 return state;
222 }
223
224 std::shared_ptr<Routine> SetupProcessor::routine(const State &state)
225 {
226 auto routine = routineCache->query(state);
227
228 if(!routine)
229 {
230 SetupRoutine *generator = new SetupRoutine(state);
231 generator->generate();
232 routine = generator->getRoutine();
233 delete generator;
234
235 routineCache->add(state, routine);
236 }
237
238 return routine;
239 }
240
241 void SetupProcessor::setRoutineCacheSize(int cacheSize)
242 {
243 delete routineCache;
244 routineCache = new RoutineCache<State>(clamp(cacheSize, 1, 65536));
245 }
246}
247