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 "Pipeline/PixelRoutine.hpp"
20 #include "Vulkan/VkDebug.hpp"
21 
22 #include <cstring>
23 
24 namespace sw
25 {
26 	FilterType Sampler::maximumTextureFilterQuality = FILTER_LINEAR;
27 	MipmapType Sampler::maximumMipmapFilterQuality = MIPMAP_POINT;
28 
State()29 	Sampler::State::State()
30 	{
31 		memset(this, 0, sizeof(State));
32 	}
33 
Sampler()34 	Sampler::Sampler()
35 	{
36 		// FIXME: Mipmap::init
37 		static const unsigned int zero = 0x00FF00FF;
38 
39 		for(int level = 0; level < MIPMAP_LEVELS; level++)
40 		{
41 			Mipmap &mipmap = texture.mipmap[level];
42 
43 			memset(&mipmap, 0, sizeof(Mipmap));
44 
45 			for(int face = 0; face < 6; face++)
46 			{
47 				mipmap.buffer[face] = &zero;
48 			}
49 		}
50 
51 		externalTextureFormat = VK_FORMAT_UNDEFINED;
52 		internalTextureFormat = VK_FORMAT_UNDEFINED;
53 		textureType = TEXTURE_NULL;
54 
55 		textureFilter = FILTER_LINEAR;
56 		addressingModeU = ADDRESSING_WRAP;
57 		addressingModeV = ADDRESSING_WRAP;
58 		addressingModeW = ADDRESSING_WRAP;
59 		mipmapFilterState = MIPMAP_NONE;
60 		sRGB = false;
61 		gather = false;
62 		highPrecisionFiltering = false;
63 		border = 0;
64 
65 		swizzleR = SWIZZLE_RED;
66 		swizzleG = SWIZZLE_GREEN;
67 		swizzleB = SWIZZLE_BLUE;
68 		swizzleA = SWIZZLE_ALPHA;
69 
70 		compare = COMPARE_BYPASS;
71 
72 		texture.LOD = 0.0f;
73 		exp2LOD = 1.0f;
74 
75 		texture.baseLevel = 0;
76 		texture.maxLevel = 1000;
77 		texture.maxLod = MAX_TEXTURE_LOD;
78 		texture.minLod = 0;
79 	}
80 
~Sampler()81 	Sampler::~Sampler()
82 	{
83 	}
84 
samplerState() const85 	Sampler::State Sampler::samplerState() const
86 	{
87 		State state;
88 
89 		if(textureType != TEXTURE_NULL)
90 		{
91 			state.textureType = textureType;
92 			state.textureFormat = internalTextureFormat;
93 			state.textureFilter = getTextureFilter();
94 			state.addressingModeU = getAddressingModeU();
95 			state.addressingModeV = getAddressingModeV();
96 			state.addressingModeW = getAddressingModeW();
97 			state.mipmapFilter = mipmapFilter();
98 			state.sRGB = (sRGB && Surface::isSRGBreadable(externalTextureFormat)) || Surface::isSRGBformat(internalTextureFormat);
99 			state.swizzleR = swizzleR;
100 			state.swizzleG = swizzleG;
101 			state.swizzleB = swizzleB;
102 			state.swizzleA = swizzleA;
103 			state.highPrecisionFiltering = highPrecisionFiltering;
104 			state.compare = getCompareFunc();
105 
106 			#if PERF_PROFILE
107 				state.compressedFormat = Surface::isCompressed(externalTextureFormat);
108 			#endif
109 		}
110 
111 		return state;
112 	}
113 
setTextureLevel(int face,int level,Surface * surface,TextureType type)114 	void Sampler::setTextureLevel(int face, int level, Surface *surface, TextureType type)
115 	{
116 		if(surface)
117 		{
118 			Mipmap &mipmap = texture.mipmap[level];
119 
120 			border = surface->getBorder();
121 			mipmap.buffer[face] = surface->lockInternal(-border, -border, 0, LOCK_UNLOCKED, PRIVATE);
122 
123 			if(face == 0)
124 			{
125 				externalTextureFormat = surface->getExternalFormat();
126 				internalTextureFormat = surface->getInternalFormat();
127 
128 				int width = surface->getWidth();
129 				int height = surface->getHeight();
130 				int depth = surface->getDepth();
131 				int pitchP = surface->getInternalPitchP();
132 				int sliceP = surface->getInternalSliceP();
133 
134 				if(level == 0)
135 				{
136 					texture.widthHeightLOD[0] = width * exp2LOD;
137 					texture.widthHeightLOD[1] = width * exp2LOD;
138 					texture.widthHeightLOD[2] = height * exp2LOD;
139 					texture.widthHeightLOD[3] = height * exp2LOD;
140 
141 					texture.widthLOD[0] = width * exp2LOD;
142 					texture.widthLOD[1] = width * exp2LOD;
143 					texture.widthLOD[2] = width * exp2LOD;
144 					texture.widthLOD[3] = width * exp2LOD;
145 
146 					texture.heightLOD[0] = height * exp2LOD;
147 					texture.heightLOD[1] = height * exp2LOD;
148 					texture.heightLOD[2] = height * exp2LOD;
149 					texture.heightLOD[3] = height * exp2LOD;
150 
151 					texture.depthLOD[0] = depth * exp2LOD;
152 					texture.depthLOD[1] = depth * exp2LOD;
153 					texture.depthLOD[2] = depth * exp2LOD;
154 					texture.depthLOD[3] = depth * exp2LOD;
155 				}
156 
157 				if(Surface::isFloatFormat(internalTextureFormat))
158 				{
159 					mipmap.fWidth[0] = (float)width / 65536.0f;
160 					mipmap.fWidth[1] = (float)width / 65536.0f;
161 					mipmap.fWidth[2] = (float)width / 65536.0f;
162 					mipmap.fWidth[3] = (float)width / 65536.0f;
163 
164 					mipmap.fHeight[0] = (float)height / 65536.0f;
165 					mipmap.fHeight[1] = (float)height / 65536.0f;
166 					mipmap.fHeight[2] = (float)height / 65536.0f;
167 					mipmap.fHeight[3] = (float)height / 65536.0f;
168 
169 					mipmap.fDepth[0] = (float)depth / 65536.0f;
170 					mipmap.fDepth[1] = (float)depth / 65536.0f;
171 					mipmap.fDepth[2] = (float)depth / 65536.0f;
172 					mipmap.fDepth[3] = (float)depth / 65536.0f;
173 				}
174 
175 				short halfTexelU = 0x8000 / width;
176 				short halfTexelV = 0x8000 / height;
177 				short halfTexelW = 0x8000 / depth;
178 
179 				mipmap.uHalf[0] = halfTexelU;
180 				mipmap.uHalf[1] = halfTexelU;
181 				mipmap.uHalf[2] = halfTexelU;
182 				mipmap.uHalf[3] = halfTexelU;
183 
184 				mipmap.vHalf[0] = halfTexelV;
185 				mipmap.vHalf[1] = halfTexelV;
186 				mipmap.vHalf[2] = halfTexelV;
187 				mipmap.vHalf[3] = halfTexelV;
188 
189 				mipmap.wHalf[0] = halfTexelW;
190 				mipmap.wHalf[1] = halfTexelW;
191 				mipmap.wHalf[2] = halfTexelW;
192 				mipmap.wHalf[3] = halfTexelW;
193 
194 				mipmap.width[0] = width;
195 				mipmap.width[1] = width;
196 				mipmap.width[2] = width;
197 				mipmap.width[3] = width;
198 
199 				mipmap.height[0] = height;
200 				mipmap.height[1] = height;
201 				mipmap.height[2] = height;
202 				mipmap.height[3] = height;
203 
204 				mipmap.depth[0] = depth;
205 				mipmap.depth[1] = depth;
206 				mipmap.depth[2] = depth;
207 				mipmap.depth[3] = depth;
208 
209 				mipmap.onePitchP[0] = 1;
210 				mipmap.onePitchP[1] = pitchP;
211 				mipmap.onePitchP[2] = 1;
212 				mipmap.onePitchP[3] = pitchP;
213 
214 				mipmap.pitchP[0] = pitchP;
215 				mipmap.pitchP[1] = pitchP;
216 				mipmap.pitchP[2] = pitchP;
217 				mipmap.pitchP[3] = pitchP;
218 
219 				mipmap.sliceP[0] = sliceP;
220 				mipmap.sliceP[1] = sliceP;
221 				mipmap.sliceP[2] = sliceP;
222 				mipmap.sliceP[3] = sliceP;
223 
224 				if(internalTextureFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
225 				{
226 					unsigned int YStride = pitchP;
227 					unsigned int YSize = YStride * height;
228 					unsigned int CStride = align<16>(YStride / 2);
229 					unsigned int CSize = CStride * height / 2;
230 
231 					mipmap.buffer[1] = (byte*)mipmap.buffer[0] + YSize;
232 					mipmap.buffer[2] = (byte*)mipmap.buffer[1] + CSize;
233 
234 					texture.mipmap[1].width[0] = width / 2;
235 					texture.mipmap[1].width[1] = width / 2;
236 					texture.mipmap[1].width[2] = width / 2;
237 					texture.mipmap[1].width[3] = width / 2;
238 					texture.mipmap[1].height[0] = height / 2;
239 					texture.mipmap[1].height[1] = height / 2;
240 					texture.mipmap[1].height[2] = height / 2;
241 					texture.mipmap[1].height[3] = height / 2;
242 					texture.mipmap[1].onePitchP[0] = 1;
243 					texture.mipmap[1].onePitchP[1] = CStride;
244 					texture.mipmap[1].onePitchP[2] = 1;
245 					texture.mipmap[1].onePitchP[3] = CStride;
246 				}
247 			}
248 		}
249 
250 		textureType = type;
251 	}
252 
setTextureFilter(FilterType textureFilter)253 	void Sampler::setTextureFilter(FilterType textureFilter)
254 	{
255 		this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
256 	}
257 
setMipmapFilter(MipmapType mipmapFilter)258 	void Sampler::setMipmapFilter(MipmapType mipmapFilter)
259 	{
260 		mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
261 	}
262 
setGatherEnable(bool enable)263 	void Sampler::setGatherEnable(bool enable)
264 	{
265 		gather = enable;
266 	}
267 
setAddressingModeU(AddressingMode addressingMode)268 	void Sampler::setAddressingModeU(AddressingMode addressingMode)
269 	{
270 		addressingModeU = addressingMode;
271 	}
272 
setAddressingModeV(AddressingMode addressingMode)273 	void Sampler::setAddressingModeV(AddressingMode addressingMode)
274 	{
275 		addressingModeV = addressingMode;
276 	}
277 
setAddressingModeW(AddressingMode addressingMode)278 	void Sampler::setAddressingModeW(AddressingMode addressingMode)
279 	{
280 		addressingModeW = addressingMode;
281 	}
282 
setReadSRGB(bool sRGB)283 	void Sampler::setReadSRGB(bool sRGB)
284 	{
285 		this->sRGB = sRGB;
286 	}
287 
setBorderColor(const Color<float> & borderColor)288 	void Sampler::setBorderColor(const Color<float> &borderColor)
289 	{
290 		// FIXME: Compact into generic function   // FIXME: Clamp
291 		short r = iround(0xFFFF * borderColor.r);
292 		short g = iround(0xFFFF * borderColor.g);
293 		short b = iround(0xFFFF * borderColor.b);
294 		short a = iround(0xFFFF * borderColor.a);
295 
296 		texture.borderColor4[0][0] = texture.borderColor4[0][1] = texture.borderColor4[0][2] = texture.borderColor4[0][3] = r;
297 		texture.borderColor4[1][0] = texture.borderColor4[1][1] = texture.borderColor4[1][2] = texture.borderColor4[1][3] = g;
298 		texture.borderColor4[2][0] = texture.borderColor4[2][1] = texture.borderColor4[2][2] = texture.borderColor4[2][3] = b;
299 		texture.borderColor4[3][0] = texture.borderColor4[3][1] = texture.borderColor4[3][2] = texture.borderColor4[3][3] = a;
300 
301 		texture.borderColorF[0][0] = texture.borderColorF[0][1] = texture.borderColorF[0][2] = texture.borderColorF[0][3] = borderColor.r;
302 		texture.borderColorF[1][0] = texture.borderColorF[1][1] = texture.borderColorF[1][2] = texture.borderColorF[1][3] = borderColor.g;
303 		texture.borderColorF[2][0] = texture.borderColorF[2][1] = texture.borderColorF[2][2] = texture.borderColorF[2][3] = borderColor.b;
304 		texture.borderColorF[3][0] = texture.borderColorF[3][1] = texture.borderColorF[3][2] = texture.borderColorF[3][3] = borderColor.a;
305 	}
306 
setMaxAnisotropy(float maxAnisotropy)307 	void Sampler::setMaxAnisotropy(float maxAnisotropy)
308 	{
309 		texture.maxAnisotropy = maxAnisotropy;
310 	}
311 
setHighPrecisionFiltering(bool highPrecisionFiltering)312 	void Sampler::setHighPrecisionFiltering(bool highPrecisionFiltering)
313 	{
314 		this->highPrecisionFiltering = highPrecisionFiltering;
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 
setCompareFunc(CompareFunc compare)337 	void Sampler::setCompareFunc(CompareFunc compare)
338 	{
339 		this->compare = compare;
340 	}
341 
setBaseLevel(int baseLevel)342 	void Sampler::setBaseLevel(int baseLevel)
343 	{
344 		texture.baseLevel = baseLevel;
345 	}
346 
setMaxLevel(int maxLevel)347 	void Sampler::setMaxLevel(int maxLevel)
348 	{
349 		texture.maxLevel = maxLevel;
350 	}
351 
setMinLod(float minLod)352 	void Sampler::setMinLod(float minLod)
353 	{
354 		texture.minLod = clamp(minLod, 0.0f, (float)(MAX_TEXTURE_LOD));
355 	}
356 
setMaxLod(float maxLod)357 	void Sampler::setMaxLod(float maxLod)
358 	{
359 		texture.maxLod = clamp(maxLod, 0.0f, (float)(MAX_TEXTURE_LOD));
360 	}
361 
setFilterQuality(FilterType maximumFilterQuality)362 	void Sampler::setFilterQuality(FilterType maximumFilterQuality)
363 	{
364 		Sampler::maximumTextureFilterQuality = maximumFilterQuality;
365 	}
366 
setMipmapQuality(MipmapType maximumFilterQuality)367 	void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
368 	{
369 		Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
370 	}
371 
setMipmapLOD(float LOD)372 	void Sampler::setMipmapLOD(float LOD)
373 	{
374 		texture.LOD = LOD;
375 		exp2LOD = exp2(LOD);
376 	}
377 
hasTexture() const378 	bool Sampler::hasTexture() const
379 	{
380 		return textureType != TEXTURE_NULL;
381 	}
382 
hasUnsignedTexture() const383 	bool Sampler::hasUnsignedTexture() const
384 	{
385 		return Surface::isUnsignedComponent(internalTextureFormat, 0) &&
386 		       Surface::isUnsignedComponent(internalTextureFormat, 1) &&
387 		       Surface::isUnsignedComponent(internalTextureFormat, 2) &&
388 		       Surface::isUnsignedComponent(internalTextureFormat, 3);
389 	}
390 
hasCubeTexture() const391 	bool Sampler::hasCubeTexture() const
392 	{
393 		return textureType == TEXTURE_CUBE;
394 	}
395 
hasVolumeTexture() const396 	bool Sampler::hasVolumeTexture() const
397 	{
398 		return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY;
399 	}
400 
getTextureData()401 	const Texture &Sampler::getTextureData()
402 	{
403 		return texture;
404 	}
405 
mipmapFilter() const406 	MipmapType Sampler::mipmapFilter() const
407 	{
408 		if(mipmapFilterState != MIPMAP_NONE)
409 		{
410 			for(int i = 1; i < MIPMAP_LEVELS; i++)
411 			{
412 				if(texture.mipmap[0].buffer[0] != texture.mipmap[i].buffer[0])
413 				{
414 					return mipmapFilterState;
415 				}
416 			}
417 		}
418 
419 		// Only one mipmap level
420 		return MIPMAP_NONE;
421 	}
422 
getTextureType() const423 	TextureType Sampler::getTextureType() const
424 	{
425 		return textureType;
426 	}
427 
getTextureFilter() const428 	FilterType Sampler::getTextureFilter() const
429 	{
430 		// Don't filter 1x1 textures.
431 		if(texture.mipmap[0].width[0] == 1 && texture.mipmap[0].height[0] == 1 && texture.mipmap[0].depth[0] == 1)
432 		{
433 			if(mipmapFilter() == MIPMAP_NONE)
434 			{
435 				return FILTER_POINT;
436 			}
437 		}
438 
439 		FilterType filter = textureFilter;
440 
441 		if(gather && Surface::componentCount(internalTextureFormat) == 1)
442 		{
443 			filter = FILTER_GATHER;
444 		}
445 
446 		if(textureType != TEXTURE_2D || texture.maxAnisotropy == 1.0f)
447 		{
448 			return (FilterType)min(filter, FILTER_LINEAR);
449 		}
450 
451 		return filter;
452 	}
453 
getAddressingModeU() const454 	AddressingMode Sampler::getAddressingModeU() const
455 	{
456 		if(textureType == TEXTURE_CUBE)
457 		{
458 			return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP;
459 		}
460 
461 		return addressingModeU;
462 	}
463 
getAddressingModeV() const464 	AddressingMode Sampler::getAddressingModeV() const
465 	{
466 		if(textureType == TEXTURE_CUBE)
467 		{
468 			return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP;
469 		}
470 
471 		return addressingModeV;
472 	}
473 
getAddressingModeW() const474 	AddressingMode Sampler::getAddressingModeW() const
475 	{
476 		if(textureType == TEXTURE_2D_ARRAY ||
477 		   textureType == TEXTURE_2D ||
478 		   textureType == TEXTURE_CUBE ||
479 		   textureType == TEXTURE_RECTANGLE)
480 		{
481 			return ADDRESSING_LAYER;
482 		}
483 
484 		return addressingModeW;
485 	}
486 
getCompareFunc() const487 	CompareFunc Sampler::getCompareFunc() const
488 	{
489 		if(getTextureFilter() == FILTER_GATHER)
490 		{
491 			return COMPARE_BYPASS;
492 		}
493 
494 		return compare;
495 	}
496 }
497