blob: c6cec5e5203bf165105eb4a95a31ca139664e627 [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
John Bauman89401822014-05-06 15:04:28 -04002//
Nicolas Capens0bac2852016-05-07 06:09:58 -04003// 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
John Bauman89401822014-05-06 15:04:28 -04006//
Nicolas Capens0bac2852016-05-07 06:09:58 -04007// http://www.apache.org/licenses/LICENSE-2.0
John Bauman89401822014-05-06 15:04:28 -04008//
Nicolas Capens0bac2852016-05-07 06:09:58 -04009// 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.
John Bauman89401822014-05-06 15:04:28 -040014
15#include "Sampler.hpp"
16
John Bauman89401822014-05-06 15:04:28 -040017#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
Nicolas Capens8e8a7e82015-09-01 14:39:57 -040039 static const unsigned int zero = 0x00FF00FF;
John Bauman89401822014-05-06 15:04:28 -040040
41 for(int level = 0; level < MIPMAP_LEVELS; level++)
42 {
43 Mipmap &mipmap = texture.mipmap[level];
44
45 memset(&mipmap, 0, sizeof(Mipmap));
46
Nicolas Capens7bb62682016-02-08 11:30:56 -050047 for(int face = 0; face < 6; face++)
John Bauman89401822014-05-06 15:04:28 -040048 {
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
Alexis Hetu43da5682015-10-21 15:36:50 -040069 swizzleR = SWIZZLE_RED;
70 swizzleG = SWIZZLE_GREEN;
71 swizzleB = SWIZZLE_BLUE;
72 swizzleA = SWIZZLE_ALPHA;
73
John Bauman89401822014-05-06 15:04:28 -040074 texture.LOD = 0.0f;
75 exp2LOD = 1.0f;
Alexis Hetu112d81f2016-06-07 12:36:35 -040076
77 texture.baseLevel = 0;
78 texture.maxLevel = 1000;
Meng-Lin Wu2fce5822016-06-07 16:15:12 -040079 texture.maxLod = MIPMAP_LEVELS - 2; // Trilinear accesses lod+1
80 texture.minLod = 0;
John Bauman89401822014-05-06 15:04:28 -040081 }
82
83 Sampler::~Sampler()
84 {
85 }
86
87 Sampler::State Sampler::samplerState() const
88 {
89 State state;
90
91 if(textureType != TEXTURE_NULL)
92 {
93 state.textureType = textureType;
94 state.textureFormat = internalTextureFormat;
95 state.textureFilter = getTextureFilter();
96 state.addressingModeU = getAddressingModeU();
97 state.addressingModeV = getAddressingModeV();
98 state.addressingModeW = getAddressingModeW();
99 state.mipmapFilter = mipmapFilter();
100 state.hasNPOTTexture = hasNPOTTexture();
101 state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat);
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400102 state.swizzleR = swizzleR;
103 state.swizzleG = swizzleG;
104 state.swizzleB = swizzleB;
105 state.swizzleA = swizzleA;
John Bauman89401822014-05-06 15:04:28 -0400106
107 #if PERF_PROFILE
108 state.compressedFormat = Surface::isCompressed(externalTextureFormat);
109 #endif
110 }
111
112 return state;
113 }
114
115 void Sampler::setTextureLevel(int face, int level, Surface *surface, TextureType type)
116 {
117 if(surface)
118 {
119 Mipmap &mipmap = texture.mipmap[level];
120
121 mipmap.buffer[face] = surface->lockInternal(0, 0, 0, LOCK_UNLOCKED, PRIVATE);
122
123 if(face == 0)
124 {
125 externalTextureFormat = surface->getExternalFormat();
126 internalTextureFormat = surface->getInternalFormat();
127
Nicolas Capens3779ea92015-06-10 13:43:52 -0400128 int width = surface->getWidth();
129 int height = surface->getHeight();
130 int depth = surface->getDepth();
John Bauman89401822014-05-06 15:04:28 -0400131 int pitchP = surface->getInternalPitchP();
132 int sliceP = surface->getInternalSliceP();
133
134 int logWidth = log2(width);
135 int logHeight = log2(height);
136 int logDepth = log2(depth);
137
138 if(level == 0)
139 {
140 texture.widthHeightLOD[0] = width * exp2LOD;
141 texture.widthHeightLOD[1] = width * exp2LOD;
142 texture.widthHeightLOD[2] = height * exp2LOD;
143 texture.widthHeightLOD[3] = height * exp2LOD;
144
145 texture.widthLOD[0] = width * exp2LOD;
146 texture.widthLOD[1] = width * exp2LOD;
147 texture.widthLOD[2] = width * exp2LOD;
148 texture.widthLOD[3] = width * exp2LOD;
149
150 texture.heightLOD[0] = height * exp2LOD;
151 texture.heightLOD[1] = height * exp2LOD;
152 texture.heightLOD[2] = height * exp2LOD;
153 texture.heightLOD[3] = height * exp2LOD;
154
155 texture.depthLOD[0] = depth * exp2LOD;
156 texture.depthLOD[1] = depth * exp2LOD;
157 texture.depthLOD[2] = depth * exp2LOD;
158 texture.depthLOD[3] = depth * exp2LOD;
159 }
160
161 if(!Surface::isFloatFormat(internalTextureFormat))
162 {
163 mipmap.uInt = logWidth;
164 mipmap.vInt = logHeight;
165 mipmap.wInt = logDepth;
166 mipmap.uFrac = 16 - logWidth;
167 mipmap.vFrac = 16 - logHeight;
168 mipmap.wFrac = 16 - logDepth;
169 }
170 else
171 {
172 mipmap.fWidth[0] = (float)width / 65536.0f;
173 mipmap.fWidth[1] = (float)width / 65536.0f;
174 mipmap.fWidth[2] = (float)width / 65536.0f;
175 mipmap.fWidth[3] = (float)width / 65536.0f;
176
177 mipmap.fHeight[0] = (float)height / 65536.0f;
178 mipmap.fHeight[1] = (float)height / 65536.0f;
179 mipmap.fHeight[2] = (float)height / 65536.0f;
180 mipmap.fHeight[3] = (float)height / 65536.0f;
181
182 mipmap.fDepth[0] = (float)depth / 65536.0f;
183 mipmap.fDepth[1] = (float)depth / 65536.0f;
184 mipmap.fDepth[2] = (float)depth / 65536.0f;
185 mipmap.fDepth[3] = (float)depth / 65536.0f;
186 }
187
Nicolas Capensadb305a2016-04-21 13:59:20 -0400188 short halfTexelU = 0x8000 / width;
189 short halfTexelV = 0x8000 / height;
190 short halfTexelW = 0x8000 / depth;
John Bauman89401822014-05-06 15:04:28 -0400191
192 mipmap.uHalf[0] = halfTexelU;
193 mipmap.uHalf[1] = halfTexelU;
194 mipmap.uHalf[2] = halfTexelU;
195 mipmap.uHalf[3] = halfTexelU;
196
197 mipmap.vHalf[0] = halfTexelV;
198 mipmap.vHalf[1] = halfTexelV;
199 mipmap.vHalf[2] = halfTexelV;
200 mipmap.vHalf[3] = halfTexelV;
201
202 mipmap.wHalf[0] = halfTexelW;
203 mipmap.wHalf[1] = halfTexelW;
204 mipmap.wHalf[2] = halfTexelW;
205 mipmap.wHalf[3] = halfTexelW;
206
207 mipmap.width[0] = width;
208 mipmap.width[1] = width;
209 mipmap.width[2] = width;
210 mipmap.width[3] = width;
211
212 mipmap.height[0] = height;
213 mipmap.height[1] = height;
214 mipmap.height[2] = height;
215 mipmap.height[3] = height;
216
217 mipmap.depth[0] = depth;
218 mipmap.depth[1] = depth;
219 mipmap.depth[2] = depth;
220 mipmap.depth[3] = depth;
221
222 mipmap.onePitchP[0] = 1;
223 mipmap.onePitchP[1] = pitchP;
224 mipmap.onePitchP[2] = 1;
225 mipmap.onePitchP[3] = pitchP;
226
227 mipmap.sliceP[0] = sliceP;
228 mipmap.sliceP[1] = sliceP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400229
230 if(internalTextureFormat == FORMAT_YV12_BT601 ||
231 internalTextureFormat == FORMAT_YV12_BT709 ||
232 internalTextureFormat == FORMAT_YV12_JFIF)
233 {
Nicolas Capens6ee16a12015-11-19 22:58:29 -0500234 unsigned int YStride = pitchP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400235 unsigned int YSize = YStride * height;
236 unsigned int CStride = align(YStride / 2, 16);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400237 unsigned int CSize = CStride * height / 2;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400238
239 mipmap.buffer[1] = (byte*)mipmap.buffer[0] + YSize;
240 mipmap.buffer[2] = (byte*)mipmap.buffer[1] + CSize;
241
242 texture.mipmap[1].uFrac = texture.mipmap[0].uFrac + 1;
243 texture.mipmap[1].vFrac = texture.mipmap[0].vFrac + 1;
244 texture.mipmap[1].width[0] = width / 2;
245 texture.mipmap[1].width[1] = width / 2;
246 texture.mipmap[1].width[2] = width / 2;
247 texture.mipmap[1].width[3] = width / 2;
248 texture.mipmap[1].height[0] = height / 2;
249 texture.mipmap[1].height[1] = height / 2;
250 texture.mipmap[1].height[2] = height / 2;
251 texture.mipmap[1].height[3] = height / 2;
252 texture.mipmap[1].onePitchP[0] = 1;
253 texture.mipmap[1].onePitchP[1] = CStride;
254 texture.mipmap[1].onePitchP[2] = 1;
255 texture.mipmap[1].onePitchP[3] = CStride;
256 }
John Bauman89401822014-05-06 15:04:28 -0400257 }
258 }
259
260 textureType = type;
261 }
262
263 void Sampler::setTextureFilter(FilterType textureFilter)
264 {
265 this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
266 }
267
268 void Sampler::setMipmapFilter(MipmapType mipmapFilter)
269 {
270 mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
271 }
272
273 void Sampler::setGatherEnable(bool enable)
274 {
275 gather = enable;
276 }
277
278 void Sampler::setAddressingModeU(AddressingMode addressingMode)
279 {
280 addressingModeU = addressingMode;
281 }
282
283 void Sampler::setAddressingModeV(AddressingMode addressingMode)
284 {
285 addressingModeV = addressingMode;
286 }
287
288 void Sampler::setAddressingModeW(AddressingMode addressingMode)
289 {
290 addressingModeW = addressingMode;
291 }
292
293 void Sampler::setReadSRGB(bool sRGB)
294 {
295 this->sRGB = sRGB;
296 }
297
298 void Sampler::setBorderColor(const Color<float> &borderColor)
299 {
300 // FIXME: Compact into generic function // FIXME: Clamp
301 short r = iround(0xFFFF * borderColor.r);
302 short g = iround(0xFFFF * borderColor.g);
303 short b = iround(0xFFFF * borderColor.b);
304 short a = iround(0xFFFF * borderColor.a);
305
306 texture.borderColor4[0][0] = texture.borderColor4[0][1] = texture.borderColor4[0][2] = texture.borderColor4[0][3] = r;
307 texture.borderColor4[1][0] = texture.borderColor4[1][1] = texture.borderColor4[1][2] = texture.borderColor4[1][3] = g;
308 texture.borderColor4[2][0] = texture.borderColor4[2][1] = texture.borderColor4[2][2] = texture.borderColor4[2][3] = b;
309 texture.borderColor4[3][0] = texture.borderColor4[3][1] = texture.borderColor4[3][2] = texture.borderColor4[3][3] = a;
310
311 texture.borderColorF[0][0] = texture.borderColorF[0][1] = texture.borderColorF[0][2] = texture.borderColorF[0][3] = borderColor.r;
312 texture.borderColorF[1][0] = texture.borderColorF[1][1] = texture.borderColorF[1][2] = texture.borderColorF[1][3] = borderColor.g;
313 texture.borderColorF[2][0] = texture.borderColorF[2][1] = texture.borderColorF[2][2] = texture.borderColorF[2][3] = borderColor.b;
314 texture.borderColorF[3][0] = texture.borderColorF[3][1] = texture.borderColorF[3][2] = texture.borderColorF[3][3] = borderColor.a;
315 }
316
Alexis Hetu617a5d52014-11-13 10:56:20 -0500317 void Sampler::setMaxAnisotropy(float maxAnisotropy)
John Bauman89401822014-05-06 15:04:28 -0400318 {
Alexis Hetu617a5d52014-11-13 10:56:20 -0500319 texture.maxAnisotropy = maxAnisotropy;
John Bauman89401822014-05-06 15:04:28 -0400320 }
321
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400322 void Sampler::setSwizzleR(SwizzleType swizzleR)
323 {
324 this->swizzleR = swizzleR;
325 }
Nicolas Capens7bb62682016-02-08 11:30:56 -0500326
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400327 void Sampler::setSwizzleG(SwizzleType swizzleG)
328 {
329 this->swizzleG = swizzleG;
330 }
331
332 void Sampler::setSwizzleB(SwizzleType swizzleB)
333 {
334 this->swizzleB = swizzleB;
335 }
336
337 void Sampler::setSwizzleA(SwizzleType swizzleA)
338 {
339 this->swizzleA = swizzleA;
340 }
341
Alexis Hetu95ac1872016-06-06 13:26:52 -0400342 void Sampler::setBaseLevel(int baseLevel)
343 {
344 texture.baseLevel = baseLevel;
345 }
346
347 void Sampler::setMaxLevel(int maxLevel)
348 {
349 texture.maxLevel = maxLevel;
350 }
351
Alexis Hetu112d81f2016-06-07 12:36:35 -0400352 void Sampler::setMinLod(float minLod)
353 {
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400354 texture.minLod = clamp(minLod, 0.0f, (float)(MIPMAP_LEVELS - 2));
Alexis Hetu112d81f2016-06-07 12:36:35 -0400355 }
356
357 void Sampler::setMaxLod(float maxLod)
358 {
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400359 texture.maxLod = clamp(maxLod, 0.0f, (float)(MIPMAP_LEVELS - 2));
Alexis Hetu112d81f2016-06-07 12:36:35 -0400360 }
361
John Bauman89401822014-05-06 15:04:28 -0400362 void Sampler::setFilterQuality(FilterType maximumFilterQuality)
363 {
364 Sampler::maximumTextureFilterQuality = maximumFilterQuality;
365 }
366
367 void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
368 {
369 Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
370 }
371
372 void Sampler::setMipmapLOD(float LOD)
373 {
374 texture.LOD = LOD;
375 exp2LOD = exp2(LOD);
376 }
377
378 bool Sampler::hasTexture() const
379 {
380 return textureType != TEXTURE_NULL;
381 }
382
383 bool Sampler::hasUnsignedTexture() const
384 {
385 return Surface::isUnsignedComponent(internalTextureFormat, 0) &&
386 Surface::isUnsignedComponent(internalTextureFormat, 1) &&
Nicolas Capens0bac2852016-05-07 06:09:58 -0400387 Surface::isUnsignedComponent(internalTextureFormat, 2) &&
388 Surface::isUnsignedComponent(internalTextureFormat, 3);
John Bauman89401822014-05-06 15:04:28 -0400389 }
390
391 bool Sampler::hasCubeTexture() const
392 {
393 return textureType == TEXTURE_CUBE;
394 }
395
396 bool Sampler::hasVolumeTexture() const
397 {
Alexis Hetuf15e8942015-12-01 15:13:23 -0500398 return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY;
John Bauman89401822014-05-06 15:04:28 -0400399 }
400
401 const Texture &Sampler::getTextureData()
402 {
403 return texture;
404 }
405
406 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
423 bool Sampler::hasNPOTTexture() const
424 {
425 if(textureType == TEXTURE_NULL)
426 {
427 return false;
428 }
429
Nicolas Capensadb305a2016-04-21 13:59:20 -0400430 for(int i = 0; i < MIPMAP_LEVELS; i++)
John Bauman19bac1e2014-05-06 15:23:49 -0400431 {
Nicolas Capensadb305a2016-04-21 13:59:20 -0400432 if(texture.mipmap[i].width[0] != texture.mipmap[i].onePitchP[1])
433 {
434 return true; // Shifting of the texture coordinates doesn't yield the correct address, so using multiply by pitch
435 }
John Bauman19bac1e2014-05-06 15:23:49 -0400436 }
437
John Bauman89401822014-05-06 15:04:28 -0400438 return !isPow2(texture.mipmap[0].width[0]) || !isPow2(texture.mipmap[0].height[0]) || !isPow2(texture.mipmap[0].depth[0]);
439 }
440
441 TextureType Sampler::getTextureType() const
442 {
443 return textureType;
444 }
445
446 FilterType Sampler::getTextureFilter() const
447 {
448 FilterType filter = textureFilter;
449
450 if(gather && Surface::componentCount(internalTextureFormat) == 1)
451 {
452 filter = FILTER_GATHER;
453 }
454
455 if(textureType != TEXTURE_2D || texture.maxAnisotropy == 1.0f)
456 {
457 return (FilterType)min(filter, FILTER_LINEAR);
458 }
459
460 return filter;
461 }
462
463 AddressingMode Sampler::getAddressingModeU() const
464 {
465 if(hasCubeTexture())
466 {
467 return ADDRESSING_CLAMP;
468 }
469
470 return addressingModeU;
471 }
472
473 AddressingMode Sampler::getAddressingModeV() const
474 {
475 if(hasCubeTexture())
476 {
477 return ADDRESSING_CLAMP;
478 }
479
480 return addressingModeV;
481 }
482
483 AddressingMode Sampler::getAddressingModeW() const
484 {
485 if(hasCubeTexture())
486 {
487 return ADDRESSING_CLAMP;
488 }
489
Nicolas Capens7bb62682016-02-08 11:30:56 -0500490 if(textureType == TEXTURE_2D_ARRAY || textureType == TEXTURE_2D)
491 {
492 return ADDRESSING_LAYER;
493 }
494
John Bauman89401822014-05-06 15:04:28 -0400495 return addressingModeW;
496 }
497}