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 
27 namespace sw
28 {
29 	extern bool complementaryDepthBuffer;
30 	extern bool fullPixelPositionRegister;
31 
32 	bool precacheSetup = false;
33 
computeHash()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 
operator ==(const State & state) const47 	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 
SetupProcessor(Context * context)58 	SetupProcessor::SetupProcessor(Context *context) : context(context)
59 	{
60 		routineCache = nullptr;
61 		setRoutineCacheSize(1024);
62 	}
63 
~SetupProcessor()64 	SetupProcessor::~SetupProcessor()
65 	{
66 		delete routineCache;
67 		routineCache = nullptr;
68 	}
69 
update() const70 	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 
routine(const State & state)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 
setRoutineCacheSize(int cacheSize)241 	void SetupProcessor::setRoutineCacheSize(int cacheSize)
242 	{
243 		delete routineCache;
244 		routineCache = new RoutineCache<State>(clamp(cacheSize, 1, 65536));
245 	}
246 }
247