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
26namespace sw
27{
28	FilterType Sampler::maximumTextureFilterQuality = FILTER_LINEAR;
29	MipmapType Sampler::maximumMipmapFilterQuality = MIPMAP_POINT;
30
31	Sampler::State::State()
32	{
33		memset(this, 0, sizeof(State));
34	}
35
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
78	Sampler::~Sampler()
79	{
80	}
81
82	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
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
258	void Sampler::setTextureFilter(FilterType textureFilter)
259	{
260		this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
261	}
262
263	void Sampler::setMipmapFilter(MipmapType mipmapFilter)
264	{
265		mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
266	}
267
268	void Sampler::setGatherEnable(bool enable)
269	{
270		gather = enable;
271	}
272
273	void Sampler::setAddressingModeU(AddressingMode addressingMode)
274	{
275		addressingModeU = addressingMode;
276	}
277
278	void Sampler::setAddressingModeV(AddressingMode addressingMode)
279	{
280		addressingModeV = addressingMode;
281	}
282
283	void Sampler::setAddressingModeW(AddressingMode addressingMode)
284	{
285		addressingModeW = addressingMode;
286	}
287
288	void Sampler::setReadSRGB(bool sRGB)
289	{
290		this->sRGB = sRGB;
291	}
292
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
312	void Sampler::setMaxAnisotropy(float maxAnisotropy)
313	{
314		texture.maxAnisotropy = maxAnisotropy;
315	}
316
317	void Sampler::setSwizzleR(SwizzleType swizzleR)
318	{
319		this->swizzleR = swizzleR;
320	}
321
322	void Sampler::setSwizzleG(SwizzleType swizzleG)
323	{
324		this->swizzleG = swizzleG;
325	}
326
327	void Sampler::setSwizzleB(SwizzleType swizzleB)
328	{
329		this->swizzleB = swizzleB;
330	}
331
332	void Sampler::setSwizzleA(SwizzleType swizzleA)
333	{
334		this->swizzleA = swizzleA;
335	}
336
337	void Sampler::setFilterQuality(FilterType maximumFilterQuality)
338	{
339		Sampler::maximumTextureFilterQuality = maximumFilterQuality;
340	}
341
342	void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
343	{
344		Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
345	}
346
347	void Sampler::setMipmapLOD(float LOD)
348	{
349		texture.LOD = LOD;
350		exp2LOD = exp2(LOD);
351	}
352
353	bool Sampler::hasTexture() const
354	{
355		return textureType != TEXTURE_NULL;
356	}
357
358	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
366	bool Sampler::hasCubeTexture() const
367	{
368		return textureType == TEXTURE_CUBE;
369	}
370
371	bool Sampler::hasVolumeTexture() const
372	{
373		return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY;
374	}
375
376	const Texture &Sampler::getTextureData()
377	{
378		return texture;
379	}
380
381	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
398	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
416	TextureType Sampler::getTextureType() const
417	{
418		return textureType;
419	}
420
421	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
438	AddressingMode Sampler::getAddressingModeU() const
439	{
440		if(hasCubeTexture())
441		{
442			return ADDRESSING_CLAMP;
443		}
444
445		return addressingModeU;
446	}
447
448	AddressingMode Sampler::getAddressingModeV() const
449	{
450		if(hasCubeTexture())
451		{
452			return ADDRESSING_CLAMP;
453		}
454
455		return addressingModeV;
456	}
457
458	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