blob: efac4c6507c6280dcced19fe15c6116e983bb1b7 [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"
Nicolas Capens708c24b2017-10-26 13:07:10 -040019#include "Shader/PixelRoutine.hpp"
20#include "Common/Debug.hpp"
John Bauman89401822014-05-06 15:04:28 -040021
22#include <memory.h>
23#include <string.h>
24
25namespace sw
26{
27 FilterType Sampler::maximumTextureFilterQuality = FILTER_LINEAR;
28 MipmapType Sampler::maximumMipmapFilterQuality = MIPMAP_POINT;
29
30 Sampler::State::State()
31 {
32 memset(this, 0, sizeof(State));
33 }
34
35 Sampler::Sampler()
36 {
37 // FIXME: Mipmap::init
Nicolas Capens8e8a7e82015-09-01 14:39:57 -040038 static const unsigned int zero = 0x00FF00FF;
John Bauman89401822014-05-06 15:04:28 -040039
40 for(int level = 0; level < MIPMAP_LEVELS; level++)
41 {
42 Mipmap &mipmap = texture.mipmap[level];
43
44 memset(&mipmap, 0, sizeof(Mipmap));
45
Nicolas Capens7bb62682016-02-08 11:30:56 -050046 for(int face = 0; face < 6; face++)
John Bauman89401822014-05-06 15:04:28 -040047 {
48 mipmap.buffer[face] = &zero;
49 }
John Bauman89401822014-05-06 15:04:28 -040050 }
51
52 externalTextureFormat = FORMAT_NULL;
53 internalTextureFormat = FORMAT_NULL;
54 textureType = TEXTURE_NULL;
55
56 textureFilter = FILTER_LINEAR;
57 addressingModeU = ADDRESSING_WRAP;
58 addressingModeV = ADDRESSING_WRAP;
59 addressingModeW = ADDRESSING_WRAP;
60 mipmapFilterState = MIPMAP_NONE;
61 sRGB = false;
62 gather = false;
Alexis Hetu010a4642017-07-18 14:33:04 -040063 highPrecisionFiltering = false;
Nicolas Capensd0f5d392017-11-28 15:54:59 -050064 border = 0;
John Bauman89401822014-05-06 15:04:28 -040065
Alexis Hetu43da5682015-10-21 15:36:50 -040066 swizzleR = SWIZZLE_RED;
67 swizzleG = SWIZZLE_GREEN;
68 swizzleB = SWIZZLE_BLUE;
69 swizzleA = SWIZZLE_ALPHA;
70
Nicolas Capensf878d502017-11-06 15:29:46 -050071 compare = COMPARE_BYPASS;
72
John Bauman89401822014-05-06 15:04:28 -040073 texture.LOD = 0.0f;
74 exp2LOD = 1.0f;
Alexis Hetu112d81f2016-06-07 12:36:35 -040075
76 texture.baseLevel = 0;
77 texture.maxLevel = 1000;
Alexis Hetu0e22d3a2017-08-16 13:43:33 -040078 texture.maxLod = MAX_TEXTURE_LOD;
Meng-Lin Wu2fce5822016-06-07 16:15:12 -040079 texture.minLod = 0;
John Bauman89401822014-05-06 15:04:28 -040080 }
81
82 Sampler::~Sampler()
83 {
84 }
85
86 Sampler::State Sampler::samplerState() const
87 {
88 State state;
89
90 if(textureType != TEXTURE_NULL)
91 {
92 state.textureType = textureType;
93 state.textureFormat = internalTextureFormat;
94 state.textureFilter = getTextureFilter();
95 state.addressingModeU = getAddressingModeU();
96 state.addressingModeV = getAddressingModeV();
97 state.addressingModeW = getAddressingModeW();
98 state.mipmapFilter = mipmapFilter();
Nicolas Capens5555af42017-12-14 13:14:03 -050099 state.sRGB = (sRGB && Surface::isSRGBreadable(externalTextureFormat)) || Surface::isSRGBformat(internalTextureFormat);
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400100 state.swizzleR = swizzleR;
101 state.swizzleG = swizzleG;
102 state.swizzleB = swizzleB;
103 state.swizzleA = swizzleA;
Alexis Hetu010a4642017-07-18 14:33:04 -0400104 state.highPrecisionFiltering = highPrecisionFiltering;
Nicolas Capensf878d502017-11-06 15:29:46 -0500105 state.compare = getCompareFunc();
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
Nicolas Capensd0f5d392017-11-28 15:54:59 -0500121 border = surface->getBorder();
122 mipmap.buffer[face] = surface->lockInternal(-border, -border, 0, LOCK_UNLOCKED, PRIVATE);
John Bauman89401822014-05-06 15:04:28 -0400123
124 if(face == 0)
125 {
126 externalTextureFormat = surface->getExternalFormat();
127 internalTextureFormat = surface->getInternalFormat();
128
Nicolas Capens3779ea92015-06-10 13:43:52 -0400129 int width = surface->getWidth();
130 int height = surface->getHeight();
131 int depth = surface->getDepth();
John Bauman89401822014-05-06 15:04:28 -0400132 int pitchP = surface->getInternalPitchP();
133 int sliceP = surface->getInternalSliceP();
134
John Bauman89401822014-05-06 15:04:28 -0400135 if(level == 0)
136 {
137 texture.widthHeightLOD[0] = width * exp2LOD;
138 texture.widthHeightLOD[1] = width * exp2LOD;
139 texture.widthHeightLOD[2] = height * exp2LOD;
140 texture.widthHeightLOD[3] = height * exp2LOD;
141
142 texture.widthLOD[0] = width * exp2LOD;
143 texture.widthLOD[1] = width * exp2LOD;
144 texture.widthLOD[2] = width * exp2LOD;
145 texture.widthLOD[3] = width * exp2LOD;
146
147 texture.heightLOD[0] = height * exp2LOD;
148 texture.heightLOD[1] = height * exp2LOD;
149 texture.heightLOD[2] = height * exp2LOD;
150 texture.heightLOD[3] = height * exp2LOD;
151
152 texture.depthLOD[0] = depth * exp2LOD;
153 texture.depthLOD[1] = depth * exp2LOD;
154 texture.depthLOD[2] = depth * exp2LOD;
155 texture.depthLOD[3] = depth * exp2LOD;
156 }
157
Nicolas Capens77980512016-12-02 14:22:32 -0500158 if(Surface::isFloatFormat(internalTextureFormat))
John Bauman89401822014-05-06 15:04:28 -0400159 {
160 mipmap.fWidth[0] = (float)width / 65536.0f;
161 mipmap.fWidth[1] = (float)width / 65536.0f;
162 mipmap.fWidth[2] = (float)width / 65536.0f;
163 mipmap.fWidth[3] = (float)width / 65536.0f;
164
165 mipmap.fHeight[0] = (float)height / 65536.0f;
166 mipmap.fHeight[1] = (float)height / 65536.0f;
167 mipmap.fHeight[2] = (float)height / 65536.0f;
168 mipmap.fHeight[3] = (float)height / 65536.0f;
169
170 mipmap.fDepth[0] = (float)depth / 65536.0f;
171 mipmap.fDepth[1] = (float)depth / 65536.0f;
172 mipmap.fDepth[2] = (float)depth / 65536.0f;
173 mipmap.fDepth[3] = (float)depth / 65536.0f;
174 }
175
Nicolas Capensadb305a2016-04-21 13:59:20 -0400176 short halfTexelU = 0x8000 / width;
177 short halfTexelV = 0x8000 / height;
178 short halfTexelW = 0x8000 / depth;
John Bauman89401822014-05-06 15:04:28 -0400179
180 mipmap.uHalf[0] = halfTexelU;
181 mipmap.uHalf[1] = halfTexelU;
182 mipmap.uHalf[2] = halfTexelU;
183 mipmap.uHalf[3] = halfTexelU;
184
185 mipmap.vHalf[0] = halfTexelV;
186 mipmap.vHalf[1] = halfTexelV;
187 mipmap.vHalf[2] = halfTexelV;
188 mipmap.vHalf[3] = halfTexelV;
189
190 mipmap.wHalf[0] = halfTexelW;
191 mipmap.wHalf[1] = halfTexelW;
192 mipmap.wHalf[2] = halfTexelW;
193 mipmap.wHalf[3] = halfTexelW;
194
195 mipmap.width[0] = width;
196 mipmap.width[1] = width;
197 mipmap.width[2] = width;
198 mipmap.width[3] = width;
199
200 mipmap.height[0] = height;
201 mipmap.height[1] = height;
202 mipmap.height[2] = height;
203 mipmap.height[3] = height;
204
205 mipmap.depth[0] = depth;
206 mipmap.depth[1] = depth;
207 mipmap.depth[2] = depth;
208 mipmap.depth[3] = depth;
209
210 mipmap.onePitchP[0] = 1;
211 mipmap.onePitchP[1] = pitchP;
212 mipmap.onePitchP[2] = 1;
213 mipmap.onePitchP[3] = pitchP;
214
Alexis Hetu75a61852017-07-14 14:17:14 -0400215 mipmap.pitchP[0] = pitchP;
216 mipmap.pitchP[1] = pitchP;
217 mipmap.pitchP[2] = pitchP;
218 mipmap.pitchP[3] = pitchP;
219
John Bauman89401822014-05-06 15:04:28 -0400220 mipmap.sliceP[0] = sliceP;
221 mipmap.sliceP[1] = sliceP;
Alexis Hetu75a61852017-07-14 14:17:14 -0400222 mipmap.sliceP[2] = sliceP;
223 mipmap.sliceP[3] = sliceP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400224
225 if(internalTextureFormat == FORMAT_YV12_BT601 ||
226 internalTextureFormat == FORMAT_YV12_BT709 ||
227 internalTextureFormat == FORMAT_YV12_JFIF)
228 {
Nicolas Capens6ee16a12015-11-19 22:58:29 -0500229 unsigned int YStride = pitchP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400230 unsigned int YSize = YStride * height;
Nicolas Capens419a5802018-05-08 17:20:50 -0400231 unsigned int CStride = align<16>(YStride / 2);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400232 unsigned int CSize = CStride * height / 2;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400233
234 mipmap.buffer[1] = (byte*)mipmap.buffer[0] + YSize;
235 mipmap.buffer[2] = (byte*)mipmap.buffer[1] + CSize;
236
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400237 texture.mipmap[1].width[0] = width / 2;
238 texture.mipmap[1].width[1] = width / 2;
239 texture.mipmap[1].width[2] = width / 2;
240 texture.mipmap[1].width[3] = width / 2;
241 texture.mipmap[1].height[0] = height / 2;
242 texture.mipmap[1].height[1] = height / 2;
243 texture.mipmap[1].height[2] = height / 2;
244 texture.mipmap[1].height[3] = height / 2;
245 texture.mipmap[1].onePitchP[0] = 1;
246 texture.mipmap[1].onePitchP[1] = CStride;
247 texture.mipmap[1].onePitchP[2] = 1;
248 texture.mipmap[1].onePitchP[3] = CStride;
249 }
John Bauman89401822014-05-06 15:04:28 -0400250 }
251 }
252
253 textureType = type;
254 }
255
256 void Sampler::setTextureFilter(FilterType textureFilter)
257 {
258 this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
259 }
260
261 void Sampler::setMipmapFilter(MipmapType mipmapFilter)
262 {
263 mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
264 }
265
266 void Sampler::setGatherEnable(bool enable)
267 {
268 gather = enable;
269 }
270
271 void Sampler::setAddressingModeU(AddressingMode addressingMode)
272 {
273 addressingModeU = addressingMode;
274 }
275
276 void Sampler::setAddressingModeV(AddressingMode addressingMode)
277 {
278 addressingModeV = addressingMode;
279 }
280
281 void Sampler::setAddressingModeW(AddressingMode addressingMode)
282 {
283 addressingModeW = addressingMode;
284 }
285
286 void Sampler::setReadSRGB(bool sRGB)
287 {
288 this->sRGB = sRGB;
289 }
290
291 void Sampler::setBorderColor(const Color<float> &borderColor)
292 {
293 // FIXME: Compact into generic function // FIXME: Clamp
294 short r = iround(0xFFFF * borderColor.r);
295 short g = iround(0xFFFF * borderColor.g);
296 short b = iround(0xFFFF * borderColor.b);
297 short a = iround(0xFFFF * borderColor.a);
298
299 texture.borderColor4[0][0] = texture.borderColor4[0][1] = texture.borderColor4[0][2] = texture.borderColor4[0][3] = r;
300 texture.borderColor4[1][0] = texture.borderColor4[1][1] = texture.borderColor4[1][2] = texture.borderColor4[1][3] = g;
301 texture.borderColor4[2][0] = texture.borderColor4[2][1] = texture.borderColor4[2][2] = texture.borderColor4[2][3] = b;
302 texture.borderColor4[3][0] = texture.borderColor4[3][1] = texture.borderColor4[3][2] = texture.borderColor4[3][3] = a;
303
304 texture.borderColorF[0][0] = texture.borderColorF[0][1] = texture.borderColorF[0][2] = texture.borderColorF[0][3] = borderColor.r;
305 texture.borderColorF[1][0] = texture.borderColorF[1][1] = texture.borderColorF[1][2] = texture.borderColorF[1][3] = borderColor.g;
306 texture.borderColorF[2][0] = texture.borderColorF[2][1] = texture.borderColorF[2][2] = texture.borderColorF[2][3] = borderColor.b;
307 texture.borderColorF[3][0] = texture.borderColorF[3][1] = texture.borderColorF[3][2] = texture.borderColorF[3][3] = borderColor.a;
308 }
309
Alexis Hetu617a5d52014-11-13 10:56:20 -0500310 void Sampler::setMaxAnisotropy(float maxAnisotropy)
John Bauman89401822014-05-06 15:04:28 -0400311 {
Alexis Hetu617a5d52014-11-13 10:56:20 -0500312 texture.maxAnisotropy = maxAnisotropy;
John Bauman89401822014-05-06 15:04:28 -0400313 }
314
Alexis Hetu010a4642017-07-18 14:33:04 -0400315 void Sampler::setHighPrecisionFiltering(bool highPrecisionFiltering)
316 {
317 this->highPrecisionFiltering = highPrecisionFiltering;
318 }
319
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400320 void Sampler::setSwizzleR(SwizzleType swizzleR)
321 {
322 this->swizzleR = swizzleR;
323 }
Nicolas Capens7bb62682016-02-08 11:30:56 -0500324
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400325 void Sampler::setSwizzleG(SwizzleType swizzleG)
326 {
327 this->swizzleG = swizzleG;
328 }
329
330 void Sampler::setSwizzleB(SwizzleType swizzleB)
331 {
332 this->swizzleB = swizzleB;
333 }
334
335 void Sampler::setSwizzleA(SwizzleType swizzleA)
336 {
337 this->swizzleA = swizzleA;
338 }
339
Nicolas Capensf878d502017-11-06 15:29:46 -0500340 void Sampler::setCompareFunc(CompareFunc compare)
341 {
342 this->compare = compare;
343 }
344
Alexis Hetu95ac1872016-06-06 13:26:52 -0400345 void Sampler::setBaseLevel(int baseLevel)
346 {
347 texture.baseLevel = baseLevel;
348 }
349
350 void Sampler::setMaxLevel(int maxLevel)
351 {
352 texture.maxLevel = maxLevel;
353 }
354
Alexis Hetu112d81f2016-06-07 12:36:35 -0400355 void Sampler::setMinLod(float minLod)
356 {
Alexis Hetu0e22d3a2017-08-16 13:43:33 -0400357 texture.minLod = clamp(minLod, 0.0f, (float)(MAX_TEXTURE_LOD));
Alexis Hetu112d81f2016-06-07 12:36:35 -0400358 }
359
360 void Sampler::setMaxLod(float maxLod)
361 {
Alexis Hetu0e22d3a2017-08-16 13:43:33 -0400362 texture.maxLod = clamp(maxLod, 0.0f, (float)(MAX_TEXTURE_LOD));
Alexis Hetu112d81f2016-06-07 12:36:35 -0400363 }
364
John Bauman89401822014-05-06 15:04:28 -0400365 void Sampler::setFilterQuality(FilterType maximumFilterQuality)
366 {
367 Sampler::maximumTextureFilterQuality = maximumFilterQuality;
368 }
369
370 void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
371 {
372 Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
373 }
374
375 void Sampler::setMipmapLOD(float LOD)
376 {
377 texture.LOD = LOD;
378 exp2LOD = exp2(LOD);
379 }
380
381 bool Sampler::hasTexture() const
382 {
383 return textureType != TEXTURE_NULL;
384 }
385
386 bool Sampler::hasUnsignedTexture() const
387 {
388 return Surface::isUnsignedComponent(internalTextureFormat, 0) &&
389 Surface::isUnsignedComponent(internalTextureFormat, 1) &&
Nicolas Capens0bac2852016-05-07 06:09:58 -0400390 Surface::isUnsignedComponent(internalTextureFormat, 2) &&
391 Surface::isUnsignedComponent(internalTextureFormat, 3);
John Bauman89401822014-05-06 15:04:28 -0400392 }
393
394 bool Sampler::hasCubeTexture() const
395 {
396 return textureType == TEXTURE_CUBE;
397 }
398
399 bool Sampler::hasVolumeTexture() const
400 {
Alexis Hetuf15e8942015-12-01 15:13:23 -0500401 return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY;
John Bauman89401822014-05-06 15:04:28 -0400402 }
403
Alexis Hetu88482c32018-06-05 17:05:17 -0400404 void Sampler::setSyncRequired(bool isSyncRequired)
405 {
406 syncRequired = isSyncRequired;
407 }
408
409 bool Sampler::requiresSync() const
410 {
411 return syncRequired;
412 }
413
John Bauman89401822014-05-06 15:04:28 -0400414 const Texture &Sampler::getTextureData()
415 {
416 return texture;
417 }
418
419 MipmapType Sampler::mipmapFilter() const
420 {
421 if(mipmapFilterState != MIPMAP_NONE)
422 {
423 for(int i = 1; i < MIPMAP_LEVELS; i++)
424 {
425 if(texture.mipmap[0].buffer[0] != texture.mipmap[i].buffer[0])
426 {
427 return mipmapFilterState;
428 }
429 }
430 }
431
432 // Only one mipmap level
433 return MIPMAP_NONE;
434 }
435
John Bauman89401822014-05-06 15:04:28 -0400436 TextureType Sampler::getTextureType() const
437 {
438 return textureType;
439 }
440
441 FilterType Sampler::getTextureFilter() const
442 {
Nicolas Capens2ed31492017-03-30 10:30:56 -0400443 // Don't filter 1x1 textures.
444 if(texture.mipmap[0].width[0] == 1 && texture.mipmap[0].height[0] == 1 && texture.mipmap[0].depth[0] == 1)
445 {
446 if(mipmapFilter() == MIPMAP_NONE)
447 {
448 return FILTER_POINT;
449 }
450 }
451
John Bauman89401822014-05-06 15:04:28 -0400452 FilterType filter = textureFilter;
453
454 if(gather && Surface::componentCount(internalTextureFormat) == 1)
455 {
456 filter = FILTER_GATHER;
457 }
458
459 if(textureType != TEXTURE_2D || texture.maxAnisotropy == 1.0f)
460 {
461 return (FilterType)min(filter, FILTER_LINEAR);
462 }
463
464 return filter;
465 }
466
467 AddressingMode Sampler::getAddressingModeU() const
468 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -0500469 if(textureType == TEXTURE_CUBE)
John Bauman89401822014-05-06 15:04:28 -0400470 {
Nicolas Capensd0f5d392017-11-28 15:54:59 -0500471 return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP;
John Bauman89401822014-05-06 15:04:28 -0400472 }
473
474 return addressingModeU;
475 }
476
477 AddressingMode Sampler::getAddressingModeV() const
478 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -0500479 if(textureType == TEXTURE_CUBE)
John Bauman89401822014-05-06 15:04:28 -0400480 {
Nicolas Capensd0f5d392017-11-28 15:54:59 -0500481 return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP;
John Bauman89401822014-05-06 15:04:28 -0400482 }
483
484 return addressingModeV;
485 }
486
487 AddressingMode Sampler::getAddressingModeW() const
488 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -0500489 if(textureType == TEXTURE_2D_ARRAY ||
490 textureType == TEXTURE_2D ||
Alexis Hetu0641aeb2018-05-08 14:25:40 -0400491 textureType == TEXTURE_CUBE ||
492 textureType == TEXTURE_RECTANGLE)
Nicolas Capens7bb62682016-02-08 11:30:56 -0500493 {
494 return ADDRESSING_LAYER;
495 }
496
John Bauman89401822014-05-06 15:04:28 -0400497 return addressingModeW;
498 }
Nicolas Capensf878d502017-11-06 15:29:46 -0500499
500 CompareFunc Sampler::getCompareFunc() const
501 {
502 if(getTextureFilter() == FILTER_GATHER)
503 {
504 return COMPARE_BYPASS;
505 }
506
507 if(internalTextureFormat == FORMAT_D32FS8_SHADOW)
508 {
509 return COMPARE_LESSEQUAL;
510 }
511
512 return compare;
513 }
John Bauman89401822014-05-06 15:04:28 -0400514}