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 "Sampler.hpp"
16 
17 #include "Context.hpp"
18 #include "Surface.hpp"
19 #include "CPUID.hpp"
20 #include "PixelRoutine.hpp"
21 #include "Debug.hpp"
22 
23 #include <memory.h>
24 #include <string.h>
25 
26 namespace sw
27 {
28 	FilterType Sampler::maximumTextureFilterQuality = FILTER_LINEAR;
29 	MipmapType Sampler::maximumMipmapFilterQuality = MIPMAP_POINT;
30 
State()31 	Sampler::State::State()
32 	{
33 		memset(this, 0, sizeof(State));
34 	}
35 
Sampler()36 	Sampler::Sampler()
37 	{
38 		// FIXME: Mipmap::init
39 		static const unsigned int zero = 0x00FF00FF;
40 
41 		for(int level = 0; level < MIPMAP_LEVELS; level++)
42 		{
43 			Mipmap &mipmap = texture.mipmap[level];
44 
45 			memset(&mipmap, 0, sizeof(Mipmap));
46 
47 			for(int face = 0; face < 6; face++)
48 			{
49 				mipmap.buffer[face] = &zero;
50 			}
51 
52 			mipmap.uFrac = 16;
53 			mipmap.vFrac = 16;
54 			mipmap.wFrac = 16;
55 		}
56 
57 		externalTextureFormat = FORMAT_NULL;
58 		internalTextureFormat = FORMAT_NULL;
59 		textureType = TEXTURE_NULL;
60 
61 		textureFilter = FILTER_LINEAR;
62 		addressingModeU = ADDRESSING_WRAP;
63 		addressingModeV = ADDRESSING_WRAP;
64 		addressingModeW = ADDRESSING_WRAP;
65 		mipmapFilterState = MIPMAP_NONE;
66 		sRGB = false;
67 		gather = false;
68 
69 		swizzleR = SWIZZLE_RED;
70 		swizzleG = SWIZZLE_GREEN;
71 		swizzleB = SWIZZLE_BLUE;
72 		swizzleA = SWIZZLE_ALPHA;
73 
74 		texture.LOD = 0.0f;
75 		exp2LOD = 1.0f;
76 	}
77 
~Sampler()78 	Sampler::~Sampler()
79 	{
80 	}
81 
samplerState() const82 	Sampler::State Sampler::samplerState() const
83 	{
84 		State state;
85 
86 		if(textureType != TEXTURE_NULL)
87 		{
88 			state.textureType = textureType;
89 			state.textureFormat = internalTextureFormat;
90 			state.textureFilter = getTextureFilter();
91 			state.addressingModeU = getAddressingModeU();
92 			state.addressingModeV = getAddressingModeV();
93 			state.addressingModeW = getAddressingModeW();
94 			state.mipmapFilter = mipmapFilter();
95 			state.hasNPOTTexture = hasNPOTTexture();
96 			state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat);
97 			state.swizzleR = swizzleR;
98 			state.swizzleG = swizzleG;
99 			state.swizzleB = swizzleB;
100 			state.swizzleA = swizzleA;
101 
102 			#if PERF_PROFILE
103 				state.compressedFormat = Surface::isCompressed(externalTextureFormat);
104 			#endif
105 		}
106 
107 		return state;
108 	}
109 
setTextureLevel(int face,int level,Surface * surface,TextureType type)110 	void Sampler::setTextureLevel(int face, int level, Surface *surface, TextureType type)
111 	{
112 		if(surface)
113 		{
114 			Mipmap &mipmap = texture.mipmap[level];
115 
116 			mipmap.buffer[face] = surface->lockInternal(0, 0, 0, LOCK_UNLOCKED, PRIVATE);
117 
118 			if(face == 0)
119 			{
120 				externalTextureFormat = surface->getExternalFormat();
121 				internalTextureFormat = surface->getInternalFormat();
122 
123 				int width = surface->getWidth();
124 				int height = surface->getHeight();
125 				int depth = surface->getDepth();
126 				int pitchP = surface->getInternalPitchP();
127 				int sliceP = surface->getInternalSliceP();
128 
129 				int logWidth = log2(width);
130 				int logHeight = log2(height);
131 				int logDepth = log2(depth);
132 
133 				if(level == 0)
134 				{
135 					texture.widthHeightLOD[0] = width * exp2LOD;
136 					texture.widthHeightLOD[1] = width * exp2LOD;
137 					texture.widthHeightLOD[2] = height * exp2LOD;
138 					texture.widthHeightLOD[3] = height * exp2LOD;
139 
140 					texture.widthLOD[0] = width * exp2LOD;
141 					texture.widthLOD[1] = width * exp2LOD;
142 					texture.widthLOD[2] = width * exp2LOD;
143 					texture.widthLOD[3] = width * exp2LOD;
144 
145 					texture.heightLOD[0] = height * exp2LOD;
146 					texture.heightLOD[1] = height * exp2LOD;
147 					texture.heightLOD[2] = height * exp2LOD;
148 					texture.heightLOD[3] = height * exp2LOD;
149 
150 					texture.depthLOD[0] = depth * exp2LOD;
151 					texture.depthLOD[1] = depth * exp2LOD;
152 					texture.depthLOD[2] = depth * exp2LOD;
153 					texture.depthLOD[3] = depth * exp2LOD;
154 				}
155 
156 				if(!Surface::isFloatFormat(internalTextureFormat))
157 				{
158 					mipmap.uInt = logWidth;
159 					mipmap.vInt = logHeight;
160 					mipmap.wInt = logDepth;
161 					mipmap.uFrac = 16 - logWidth;
162 					mipmap.vFrac = 16 - logHeight;
163 					mipmap.wFrac = 16 - logDepth;
164 				}
165 				else
166 				{
167 					mipmap.fWidth[0] = (float)width / 65536.0f;
168 					mipmap.fWidth[1] = (float)width / 65536.0f;
169 					mipmap.fWidth[2] = (float)width / 65536.0f;
170 					mipmap.fWidth[3] = (float)width / 65536.0f;
171 
172 					mipmap.fHeight[0] = (float)height / 65536.0f;
173 					mipmap.fHeight[1] = (float)height / 65536.0f;
174 					mipmap.fHeight[2] = (float)height / 65536.0f;
175 					mipmap.fHeight[3] = (float)height / 65536.0f;
176 
177 					mipmap.fDepth[0] = (float)depth / 65536.0f;
178 					mipmap.fDepth[1] = (float)depth / 65536.0f;
179 					mipmap.fDepth[2] = (float)depth / 65536.0f;
180 					mipmap.fDepth[3] = (float)depth / 65536.0f;
181 				}
182 
183 				short halfTexelU = 0x8000 / width;
184 				short halfTexelV = 0x8000 / height;
185 				short halfTexelW = 0x8000 / depth;
186 
187 				mipmap.uHalf[0] = halfTexelU;
188 				mipmap.uHalf[1] = halfTexelU;
189 				mipmap.uHalf[2] = halfTexelU;
190 				mipmap.uHalf[3] = halfTexelU;
191 
192 				mipmap.vHalf[0] = halfTexelV;
193 				mipmap.vHalf[1] = halfTexelV;
194 				mipmap.vHalf[2] = halfTexelV;
195 				mipmap.vHalf[3] = halfTexelV;
196 
197 				mipmap.wHalf[0] = halfTexelW;
198 				mipmap.wHalf[1] = halfTexelW;
199 				mipmap.wHalf[2] = halfTexelW;
200 				mipmap.wHalf[3] = halfTexelW;
201 
202 				mipmap.width[0] = width;
203 				mipmap.width[1] = width;
204 				mipmap.width[2] = width;
205 				mipmap.width[3] = width;
206 
207 				mipmap.height[0] = height;
208 				mipmap.height[1] = height;
209 				mipmap.height[2] = height;
210 				mipmap.height[3] = height;
211 
212 				mipmap.depth[0] = depth;
213 				mipmap.depth[1] = depth;
214 				mipmap.depth[2] = depth;
215 				mipmap.depth[3] = depth;
216 
217 				mipmap.onePitchP[0] = 1;
218 				mipmap.onePitchP[1] = pitchP;
219 				mipmap.onePitchP[2] = 1;
220 				mipmap.onePitchP[3] = pitchP;
221 
222 				mipmap.sliceP[0] = sliceP;
223 				mipmap.sliceP[1] = sliceP;
224 
225 				if(internalTextureFormat == FORMAT_YV12_BT601 ||
226 				   internalTextureFormat == FORMAT_YV12_BT709 ||
227 				   internalTextureFormat == FORMAT_YV12_JFIF)
228 				{
229 					unsigned int YStride = pitchP;
230 					unsigned int YSize = YStride * height;
231 					unsigned int CStride = align(YStride / 2, 16);
232 					unsigned int CSize = CStride * height / 2;
233 
234 					mipmap.buffer[1] = (byte*)mipmap.buffer[0] + YSize;
235 					mipmap.buffer[2] = (byte*)mipmap.buffer[1] + CSize;
236 
237 					texture.mipmap[1].uFrac = texture.mipmap[0].uFrac + 1;
238 					texture.mipmap[1].vFrac = texture.mipmap[0].vFrac + 1;
239 					texture.mipmap[1].width[0] = width / 2;
240 					texture.mipmap[1].width[1] = width / 2;
241 					texture.mipmap[1].width[2] = width / 2;
242 					texture.mipmap[1].width[3] = width / 2;
243 					texture.mipmap[1].height[0] = height / 2;
244 					texture.mipmap[1].height[1] = height / 2;
245 					texture.mipmap[1].height[2] = height / 2;
246 					texture.mipmap[1].height[3] = height / 2;
247 					texture.mipmap[1].onePitchP[0] = 1;
248 					texture.mipmap[1].onePitchP[1] = CStride;
249 					texture.mipmap[1].onePitchP[2] = 1;
250 					texture.mipmap[1].onePitchP[3] = CStride;
251 				}
252 			}
253 		}
254 
255 		textureType = type;
256 	}
257 
setTextureFilter(FilterType textureFilter)258 	void Sampler::setTextureFilter(FilterType textureFilter)
259 	{
260 		this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
261 	}
262 
setMipmapFilter(MipmapType mipmapFilter)263 	void Sampler::setMipmapFilter(MipmapType mipmapFilter)
264 	{
265 		mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
266 	}
267 
setGatherEnable(bool enable)268 	void Sampler::setGatherEnable(bool enable)
269 	{
270 		gather = enable;
271 	}
272 
setAddressingModeU(AddressingMode addressingMode)273 	void Sampler::setAddressingModeU(AddressingMode addressingMode)
274 	{
275 		addressingModeU = addressingMode;
276 	}
277 
setAddressingModeV(AddressingMode addressingMode)278 	void Sampler::setAddressingModeV(AddressingMode addressingMode)
279 	{
280 		addressingModeV = addressingMode;
281 	}
282 
setAddressingModeW(AddressingMode addressingMode)283 	void Sampler::setAddressingModeW(AddressingMode addressingMode)
284 	{
285 		addressingModeW = addressingMode;
286 	}
287 
setReadSRGB(bool sRGB)288 	void Sampler::setReadSRGB(bool sRGB)
289 	{
290 		this->sRGB = sRGB;
291 	}
292 
setBorderColor(const Color<float> & borderColor)293 	void Sampler::setBorderColor(const Color<float> &borderColor)
294 	{
295 		// FIXME: Compact into generic function   // FIXME: Clamp
296 		short r = iround(0xFFFF * borderColor.r);
297 		short g = iround(0xFFFF * borderColor.g);
298 		short b = iround(0xFFFF * borderColor.b);
299 		short a = iround(0xFFFF * borderColor.a);
300 
301 		texture.borderColor4[0][0] = texture.borderColor4[0][1] = texture.borderColor4[0][2] = texture.borderColor4[0][3] = r;
302 		texture.borderColor4[1][0] = texture.borderColor4[1][1] = texture.borderColor4[1][2] = texture.borderColor4[1][3] = g;
303 		texture.borderColor4[2][0] = texture.borderColor4[2][1] = texture.borderColor4[2][2] = texture.borderColor4[2][3] = b;
304 		texture.borderColor4[3][0] = texture.borderColor4[3][1] = texture.borderColor4[3][2] = texture.borderColor4[3][3] = a;
305 
306 		texture.borderColorF[0][0] = texture.borderColorF[0][1] = texture.borderColorF[0][2] = texture.borderColorF[0][3] = borderColor.r;
307 		texture.borderColorF[1][0] = texture.borderColorF[1][1] = texture.borderColorF[1][2] = texture.borderColorF[1][3] = borderColor.g;
308 		texture.borderColorF[2][0] = texture.borderColorF[2][1] = texture.borderColorF[2][2] = texture.borderColorF[2][3] = borderColor.b;
309 		texture.borderColorF[3][0] = texture.borderColorF[3][1] = texture.borderColorF[3][2] = texture.borderColorF[3][3] = borderColor.a;
310 	}
311 
setMaxAnisotropy(float maxAnisotropy)312 	void Sampler::setMaxAnisotropy(float maxAnisotropy)
313 	{
314 		texture.maxAnisotropy = maxAnisotropy;
315 	}
316 
setSwizzleR(SwizzleType swizzleR)317 	void Sampler::setSwizzleR(SwizzleType swizzleR)
318 	{
319 		this->swizzleR = swizzleR;
320 	}
321 
setSwizzleG(SwizzleType swizzleG)322 	void Sampler::setSwizzleG(SwizzleType swizzleG)
323 	{
324 		this->swizzleG = swizzleG;
325 	}
326 
setSwizzleB(SwizzleType swizzleB)327 	void Sampler::setSwizzleB(SwizzleType swizzleB)
328 	{
329 		this->swizzleB = swizzleB;
330 	}
331 
setSwizzleA(SwizzleType swizzleA)332 	void Sampler::setSwizzleA(SwizzleType swizzleA)
333 	{
334 		this->swizzleA = swizzleA;
335 	}
336 
setFilterQuality(FilterType maximumFilterQuality)337 	void Sampler::setFilterQuality(FilterType maximumFilterQuality)
338 	{
339 		Sampler::maximumTextureFilterQuality = maximumFilterQuality;
340 	}
341 
setMipmapQuality(MipmapType maximumFilterQuality)342 	void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
343 	{
344 		Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
345 	}
346 
setMipmapLOD(float LOD)347 	void Sampler::setMipmapLOD(float LOD)
348 	{
349 		texture.LOD = LOD;
350 		exp2LOD = exp2(LOD);
351 	}
352 
hasTexture() const353 	bool Sampler::hasTexture() const
354 	{
355 		return textureType != TEXTURE_NULL;
356 	}
357 
hasUnsignedTexture() const358 	bool Sampler::hasUnsignedTexture() const
359 	{
360 		return Surface::isUnsignedComponent(internalTextureFormat, 0) &&
361 		       Surface::isUnsignedComponent(internalTextureFormat, 1) &&
362 		       Surface::isUnsignedComponent(internalTextureFormat, 2) &&
363 		       Surface::isUnsignedComponent(internalTextureFormat, 3);
364 	}
365 
hasCubeTexture() const366 	bool Sampler::hasCubeTexture() const
367 	{
368 		return textureType == TEXTURE_CUBE;
369 	}
370 
hasVolumeTexture() const371 	bool Sampler::hasVolumeTexture() const
372 	{
373 		return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY;
374 	}
375 
getTextureData()376 	const Texture &Sampler::getTextureData()
377 	{
378 		return texture;
379 	}
380 
mipmapFilter() const381 	MipmapType Sampler::mipmapFilter() const
382 	{
383 		if(mipmapFilterState != MIPMAP_NONE)
384 		{
385 			for(int i = 1; i < MIPMAP_LEVELS; i++)
386 			{
387 				if(texture.mipmap[0].buffer[0] != texture.mipmap[i].buffer[0])
388 				{
389 					return mipmapFilterState;
390 				}
391 			}
392 		}
393 
394 		// Only one mipmap level
395 		return MIPMAP_NONE;
396 	}
397 
hasNPOTTexture() const398 	bool Sampler::hasNPOTTexture() const
399 	{
400 		if(textureType == TEXTURE_NULL)
401 		{
402 			return false;
403 		}
404 
405 		for(int i = 0; i < MIPMAP_LEVELS; i++)
406 		{
407 			if(texture.mipmap[i].width[0] != texture.mipmap[i].onePitchP[1])
408 			{
409 				return true;   // Shifting of the texture coordinates doesn't yield the correct address, so using multiply by pitch
410 			}
411 		}
412 
413 		return !isPow2(texture.mipmap[0].width[0]) || !isPow2(texture.mipmap[0].height[0]) || !isPow2(texture.mipmap[0].depth[0]);
414 	}
415 
getTextureType() const416 	TextureType Sampler::getTextureType() const
417 	{
418 		return textureType;
419 	}
420 
getTextureFilter() const421 	FilterType Sampler::getTextureFilter() const
422 	{
423 		FilterType filter = textureFilter;
424 
425 		if(gather && Surface::componentCount(internalTextureFormat) == 1)
426 		{
427 			filter = FILTER_GATHER;
428 		}
429 
430 		if(textureType != TEXTURE_2D || texture.maxAnisotropy == 1.0f)
431 		{
432 			return (FilterType)min(filter, FILTER_LINEAR);
433 		}
434 
435 		return filter;
436 	}
437 
getAddressingModeU() const438 	AddressingMode Sampler::getAddressingModeU() const
439 	{
440 		if(hasCubeTexture())
441 		{
442 			return ADDRESSING_CLAMP;
443 		}
444 
445 		return addressingModeU;
446 	}
447 
getAddressingModeV() const448 	AddressingMode Sampler::getAddressingModeV() const
449 	{
450 		if(hasCubeTexture())
451 		{
452 			return ADDRESSING_CLAMP;
453 		}
454 
455 		return addressingModeV;
456 	}
457 
getAddressingModeW() const458 	AddressingMode Sampler::getAddressingModeW() const
459 	{
460 		if(hasCubeTexture())
461 		{
462 			return ADDRESSING_CLAMP;
463 		}
464 
465 		if(textureType == TEXTURE_2D_ARRAY || textureType == TEXTURE_2D)
466 		{
467 			return ADDRESSING_LAYER;
468 		}
469 
470 		return addressingModeW;
471 	}
472 }
473