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 "SetupRoutine.hpp"
18#include "Primitive.hpp"
19#include "Polygon.hpp"
20#include "Context.hpp"
21#include "Renderer.hpp"
22#include "Constants.hpp"
23#include "Debug.hpp"
24
25namespace sw
26{
27	extern bool complementaryDepthBuffer;
28	extern bool fullPixelPositionRegister;
29
30	bool precacheSetup = false;
31
32	unsigned int SetupProcessor::States::computeHash()
33	{
34		unsigned int *state = (unsigned int*)this;
35		unsigned int hash = 0;
36
37		for(unsigned int i = 0; i < sizeof(States) / 4; i++)
38		{
39			hash ^= state[i];
40		}
41
42		return hash;
43	}
44
45	SetupProcessor::State::State(int i)
46	{
47		memset(this, 0, sizeof(State));
48	}
49
50	bool SetupProcessor::State::operator==(const State &state) const
51	{
52		if(hash != state.hash)
53		{
54			return false;
55		}
56
57		return memcmp(static_cast<const States*>(this), static_cast<const States*>(&state), sizeof(States)) == 0;
58	}
59
60	SetupProcessor::SetupProcessor(Context *context) : context(context)
61	{
62		routineCache = 0;
63		setRoutineCacheSize(1024);
64	}
65
66	SetupProcessor::~SetupProcessor()
67	{
68		delete routineCache;
69		routineCache = 0;
70	}
71
72	SetupProcessor::State SetupProcessor::update() const
73	{
74		State state;
75
76		bool vPosZW = (context->pixelShader && context->pixelShader->isVPosDeclared() && fullPixelPositionRegister);
77
78		state.isDrawPoint = context->isDrawPoint(true);
79		state.isDrawLine = context->isDrawLine(true);
80		state.isDrawTriangle = context->isDrawTriangle(false);
81		state.isDrawSolidTriangle = context->isDrawTriangle(true);
82		state.interpolateZ = context->depthBufferActive() || context->pixelFogActive() != FOG_NONE || vPosZW;
83		state.interpolateW = context->perspectiveActive() || vPosZW;
84		state.perspective = context->perspectiveActive();
85		state.pointSprite = context->pointSpriteActive();
86		state.cullMode = context->cullMode;
87		state.twoSidedStencil = context->stencilActive() && context->twoSidedStencil;
88		state.slopeDepthBias = slopeDepthBias != 0.0f;
89		state.vFace = context->pixelShader && context->pixelShader->isVFaceDeclared();
90
91		state.positionRegister = Pos;
92		state.pointSizeRegister = Unused;
93
94		state.multiSample = context->getMultiSampleCount();
95		state.rasterizerDiscard = context->rasterizerDiscard;
96
97		if(context->vertexShader)
98		{
99			state.positionRegister = context->vertexShader->getPositionRegister();
100			state.pointSizeRegister = context->vertexShader->getPointSizeRegister();
101		}
102		else if(context->pointSizeActive())
103		{
104			state.pointSizeRegister = Pts;
105		}
106
107		for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
108		{
109			for(int component = 0; component < 4; component++)
110			{
111				state.gradient[interpolant][component].attribute = Unused;
112				state.gradient[interpolant][component].flat = false;
113				state.gradient[interpolant][component].wrap = false;
114			}
115		}
116
117		state.fog.attribute = Unused;
118		state.fog.flat = false;
119		state.fog.wrap = false;
120
121		const bool point = context->isDrawPoint(true);
122		const bool sprite = context->pointSpriteActive();
123		const bool flatShading = (context->shadingMode == SHADING_FLAT) || point;
124
125		if(context->vertexShader && context->pixelShader)
126		{
127			for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
128			{
129				for(int component = 0; component < 4; component++)
130				{
131					int project = context->isProjectionComponent(interpolant - 2, component) ? 1 : 0;
132					const Shader::Semantic& semantic = context->pixelShader->getInput(interpolant, component - project);
133
134					if(semantic.active())
135					{
136						int input = interpolant;
137						for(int i = 0; i < MAX_VERTEX_OUTPUTS; i++)
138						{
139							if(semantic == context->vertexShader->getOutput(i, component - project))
140							{
141								input = i;
142								break;
143							}
144						}
145
146						bool flat = point;
147
148						switch(semantic.usage)
149						{
150						case Shader::USAGE_TEXCOORD: flat = point && !sprite;             break;
151						case Shader::USAGE_COLOR:    flat = semantic.flat || flatShading; break;
152						}
153
154						state.gradient[interpolant][component].attribute = input;
155						state.gradient[interpolant][component].flat = flat;
156					}
157				}
158			}
159		}
160		else if(context->preTransformed && context->pixelShader)
161		{
162			for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
163			{
164				for(int component = 0; component < 4; component++)
165				{
166					const Shader::Semantic& semantic = context->pixelShader->getInput(interpolant, component);
167
168					switch(semantic.usage)
169					{
170					case 0xFF:
171						break;
172					case Shader::USAGE_TEXCOORD:
173						state.gradient[interpolant][component].attribute = T0 + semantic.index;
174						state.gradient[interpolant][component].flat = semantic.flat || (point && !sprite);
175						break;
176					case Shader::USAGE_COLOR:
177						state.gradient[interpolant][component].attribute = C0 + semantic.index;
178						state.gradient[interpolant][component].flat = semantic.flat || flatShading;
179						break;
180					default:
181						ASSERT(false);
182					}
183				}
184			}
185		}
186		else if(context->pixelShaderVersion() < 0x0300)
187		{
188			for(int coordinate = 0; coordinate < 8; coordinate++)
189			{
190				for(int component = 0; component < 4; component++)
191				{
192					if(context->textureActive(coordinate, component))
193					{
194						state.texture[coordinate][component].attribute = T0 + coordinate;
195						state.texture[coordinate][component].flat = point && !sprite;
196						state.texture[coordinate][component].wrap = (context->textureWrap[coordinate] & (1 << component)) != 0;
197					}
198				}
199			}
200
201			for(int color = 0; color < 2; color++)
202			{
203				for(int component = 0; component < 4; component++)
204				{
205					if(context->colorActive(color, component))
206					{
207						state.color[color][component].attribute = C0 + color;
208						state.color[color][component].flat = flatShading;
209					}
210				}
211			}
212		}
213		else ASSERT(false);
214
215		if(context->fogActive())
216		{
217			state.fog.attribute = Fog;
218			state.fog.flat = point;
219		}
220
221		state.hash = state.computeHash();
222
223		return state;
224	}
225
226	Routine *SetupProcessor::routine(const State &state)
227	{
228		Routine *routine = routineCache->query(state);
229
230		if(!routine)
231		{
232			SetupRoutine *generator = new SetupRoutine(state);
233			generator->generate();
234			routine = generator->getRoutine();
235			delete generator;
236
237			routineCache->add(state, routine);
238		}
239
240		return routine;
241	}
242
243	void SetupProcessor::setRoutineCacheSize(int cacheSize)
244	{
245		delete routineCache;
246		routineCache = new RoutineCache<State>(clamp(cacheSize, 1, 65536), precacheSetup ? "sw-setup" : 0);
247	}
248}
249