blob: 7518715fcbf2494af2bd373afa956b81f3a3da63 [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
17#include "MetaMacro.hpp"
18#include "Context.hpp"
19#include "Surface.hpp"
20#include "CPUID.hpp"
21#include "PixelRoutine.hpp"
22#include "Debug.hpp"
23
24#include <memory.h>
25#include <string.h>
26
27namespace sw
28{
29 FilterType Sampler::maximumTextureFilterQuality = FILTER_LINEAR;
30 MipmapType Sampler::maximumMipmapFilterQuality = MIPMAP_POINT;
31
32 Sampler::State::State()
33 {
34 memset(this, 0, sizeof(State));
35 }
36
37 Sampler::Sampler()
38 {
39 // FIXME: Mipmap::init
Nicolas Capens8e8a7e82015-09-01 14:39:57 -040040 static const unsigned int zero = 0x00FF00FF;
John Bauman89401822014-05-06 15:04:28 -040041
42 for(int level = 0; level < MIPMAP_LEVELS; level++)
43 {
44 Mipmap &mipmap = texture.mipmap[level];
45
46 memset(&mipmap, 0, sizeof(Mipmap));
47
Nicolas Capens7bb62682016-02-08 11:30:56 -050048 for(int face = 0; face < 6; face++)
John Bauman89401822014-05-06 15:04:28 -040049 {
50 mipmap.buffer[face] = &zero;
51 }
52
53 mipmap.uFrac = 16;
54 mipmap.vFrac = 16;
55 mipmap.wFrac = 16;
56 }
57
58 externalTextureFormat = FORMAT_NULL;
59 internalTextureFormat = FORMAT_NULL;
60 textureType = TEXTURE_NULL;
61
62 textureFilter = FILTER_LINEAR;
63 addressingModeU = ADDRESSING_WRAP;
64 addressingModeV = ADDRESSING_WRAP;
65 addressingModeW = ADDRESSING_WRAP;
66 mipmapFilterState = MIPMAP_NONE;
67 sRGB = false;
68 gather = false;
69
Alexis Hetu43da5682015-10-21 15:36:50 -040070 swizzleR = SWIZZLE_RED;
71 swizzleG = SWIZZLE_GREEN;
72 swizzleB = SWIZZLE_BLUE;
73 swizzleA = SWIZZLE_ALPHA;
74
John Bauman89401822014-05-06 15:04:28 -040075 texture.LOD = 0.0f;
76 exp2LOD = 1.0f;
77 }
78
79 Sampler::~Sampler()
80 {
81 }
82
83 Sampler::State Sampler::samplerState() const
84 {
85 State state;
86
87 if(textureType != TEXTURE_NULL)
88 {
89 state.textureType = textureType;
90 state.textureFormat = internalTextureFormat;
91 state.textureFilter = getTextureFilter();
92 state.addressingModeU = getAddressingModeU();
93 state.addressingModeV = getAddressingModeV();
94 state.addressingModeW = getAddressingModeW();
95 state.mipmapFilter = mipmapFilter();
96 state.hasNPOTTexture = hasNPOTTexture();
97 state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat);
Alexis Hetu1d01aa32015-09-29 11:50:05 -040098 state.swizzleR = swizzleR;
99 state.swizzleG = swizzleG;
100 state.swizzleB = swizzleB;
101 state.swizzleA = swizzleA;
John Bauman89401822014-05-06 15:04:28 -0400102
103 #if PERF_PROFILE
104 state.compressedFormat = Surface::isCompressed(externalTextureFormat);
105 #endif
106 }
107
108 return state;
109 }
110
111 void Sampler::setTextureLevel(int face, int level, Surface *surface, TextureType type)
112 {
113 if(surface)
114 {
115 Mipmap &mipmap = texture.mipmap[level];
116
117 mipmap.buffer[face] = surface->lockInternal(0, 0, 0, LOCK_UNLOCKED, PRIVATE);
118
119 if(face == 0)
120 {
121 externalTextureFormat = surface->getExternalFormat();
122 internalTextureFormat = surface->getInternalFormat();
123
Nicolas Capens3779ea92015-06-10 13:43:52 -0400124 int width = surface->getWidth();
125 int height = surface->getHeight();
126 int depth = surface->getDepth();
John Bauman89401822014-05-06 15:04:28 -0400127 int pitchP = surface->getInternalPitchP();
128 int sliceP = surface->getInternalSliceP();
129
130 int logWidth = log2(width);
131 int logHeight = log2(height);
132 int logDepth = log2(depth);
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.uInt = logWidth;
160 mipmap.vInt = logHeight;
161 mipmap.wInt = logDepth;
162 mipmap.uFrac = 16 - logWidth;
163 mipmap.vFrac = 16 - logHeight;
164 mipmap.wFrac = 16 - logDepth;
165 }
166 else
167 {
168 mipmap.fWidth[0] = (float)width / 65536.0f;
169 mipmap.fWidth[1] = (float)width / 65536.0f;
170 mipmap.fWidth[2] = (float)width / 65536.0f;
171 mipmap.fWidth[3] = (float)width / 65536.0f;
172
173 mipmap.fHeight[0] = (float)height / 65536.0f;
174 mipmap.fHeight[1] = (float)height / 65536.0f;
175 mipmap.fHeight[2] = (float)height / 65536.0f;
176 mipmap.fHeight[3] = (float)height / 65536.0f;
177
178 mipmap.fDepth[0] = (float)depth / 65536.0f;
179 mipmap.fDepth[1] = (float)depth / 65536.0f;
180 mipmap.fDepth[2] = (float)depth / 65536.0f;
181 mipmap.fDepth[3] = (float)depth / 65536.0f;
182 }
183
Nicolas Capensadb305a2016-04-21 13:59:20 -0400184 short halfTexelU = 0x8000 / width;
185 short halfTexelV = 0x8000 / height;
186 short halfTexelW = 0x8000 / depth;
John Bauman89401822014-05-06 15:04:28 -0400187
188 mipmap.uHalf[0] = halfTexelU;
189 mipmap.uHalf[1] = halfTexelU;
190 mipmap.uHalf[2] = halfTexelU;
191 mipmap.uHalf[3] = halfTexelU;
192
193 mipmap.vHalf[0] = halfTexelV;
194 mipmap.vHalf[1] = halfTexelV;
195 mipmap.vHalf[2] = halfTexelV;
196 mipmap.vHalf[3] = halfTexelV;
197
198 mipmap.wHalf[0] = halfTexelW;
199 mipmap.wHalf[1] = halfTexelW;
200 mipmap.wHalf[2] = halfTexelW;
201 mipmap.wHalf[3] = halfTexelW;
202
203 mipmap.width[0] = width;
204 mipmap.width[1] = width;
205 mipmap.width[2] = width;
206 mipmap.width[3] = width;
207
208 mipmap.height[0] = height;
209 mipmap.height[1] = height;
210 mipmap.height[2] = height;
211 mipmap.height[3] = height;
212
213 mipmap.depth[0] = depth;
214 mipmap.depth[1] = depth;
215 mipmap.depth[2] = depth;
216 mipmap.depth[3] = depth;
217
218 mipmap.onePitchP[0] = 1;
219 mipmap.onePitchP[1] = pitchP;
220 mipmap.onePitchP[2] = 1;
221 mipmap.onePitchP[3] = pitchP;
222
223 mipmap.sliceP[0] = sliceP;
224 mipmap.sliceP[1] = sliceP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400225
226 if(internalTextureFormat == FORMAT_YV12_BT601 ||
227 internalTextureFormat == FORMAT_YV12_BT709 ||
228 internalTextureFormat == FORMAT_YV12_JFIF)
229 {
Nicolas Capens6ee16a12015-11-19 22:58:29 -0500230 unsigned int YStride = pitchP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400231 unsigned int YSize = YStride * height;
232 unsigned int CStride = align(YStride / 2, 16);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400233 unsigned int CSize = CStride * height / 2;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400234
235 mipmap.buffer[1] = (byte*)mipmap.buffer[0] + YSize;
236 mipmap.buffer[2] = (byte*)mipmap.buffer[1] + CSize;
237
238 texture.mipmap[1].uFrac = texture.mipmap[0].uFrac + 1;
239 texture.mipmap[1].vFrac = texture.mipmap[0].vFrac + 1;
240 texture.mipmap[1].width[0] = width / 2;
241 texture.mipmap[1].width[1] = width / 2;
242 texture.mipmap[1].width[2] = width / 2;
243 texture.mipmap[1].width[3] = width / 2;
244 texture.mipmap[1].height[0] = height / 2;
245 texture.mipmap[1].height[1] = height / 2;
246 texture.mipmap[1].height[2] = height / 2;
247 texture.mipmap[1].height[3] = height / 2;
248 texture.mipmap[1].onePitchP[0] = 1;
249 texture.mipmap[1].onePitchP[1] = CStride;
250 texture.mipmap[1].onePitchP[2] = 1;
251 texture.mipmap[1].onePitchP[3] = CStride;
252 }
John Bauman89401822014-05-06 15:04:28 -0400253 }
254 }
255
256 textureType = type;
257 }
258
259 void Sampler::setTextureFilter(FilterType textureFilter)
260 {
261 this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
262 }
263
264 void Sampler::setMipmapFilter(MipmapType mipmapFilter)
265 {
266 mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
267 }
268
269 void Sampler::setGatherEnable(bool enable)
270 {
271 gather = enable;
272 }
273
274 void Sampler::setAddressingModeU(AddressingMode addressingMode)
275 {
276 addressingModeU = addressingMode;
277 }
278
279 void Sampler::setAddressingModeV(AddressingMode addressingMode)
280 {
281 addressingModeV = addressingMode;
282 }
283
284 void Sampler::setAddressingModeW(AddressingMode addressingMode)
285 {
286 addressingModeW = addressingMode;
287 }
288
289 void Sampler::setReadSRGB(bool sRGB)
290 {
291 this->sRGB = sRGB;
292 }
293
294 void Sampler::setBorderColor(const Color<float> &borderColor)
295 {
296 // FIXME: Compact into generic function // FIXME: Clamp
297 short r = iround(0xFFFF * borderColor.r);
298 short g = iround(0xFFFF * borderColor.g);
299 short b = iround(0xFFFF * borderColor.b);
300 short a = iround(0xFFFF * borderColor.a);
301
302 texture.borderColor4[0][0] = texture.borderColor4[0][1] = texture.borderColor4[0][2] = texture.borderColor4[0][3] = r;
303 texture.borderColor4[1][0] = texture.borderColor4[1][1] = texture.borderColor4[1][2] = texture.borderColor4[1][3] = g;
304 texture.borderColor4[2][0] = texture.borderColor4[2][1] = texture.borderColor4[2][2] = texture.borderColor4[2][3] = b;
305 texture.borderColor4[3][0] = texture.borderColor4[3][1] = texture.borderColor4[3][2] = texture.borderColor4[3][3] = a;
306
307 texture.borderColorF[0][0] = texture.borderColorF[0][1] = texture.borderColorF[0][2] = texture.borderColorF[0][3] = borderColor.r;
308 texture.borderColorF[1][0] = texture.borderColorF[1][1] = texture.borderColorF[1][2] = texture.borderColorF[1][3] = borderColor.g;
309 texture.borderColorF[2][0] = texture.borderColorF[2][1] = texture.borderColorF[2][2] = texture.borderColorF[2][3] = borderColor.b;
310 texture.borderColorF[3][0] = texture.borderColorF[3][1] = texture.borderColorF[3][2] = texture.borderColorF[3][3] = borderColor.a;
311 }
312
Alexis Hetu617a5d52014-11-13 10:56:20 -0500313 void Sampler::setMaxAnisotropy(float maxAnisotropy)
John Bauman89401822014-05-06 15:04:28 -0400314 {
Alexis Hetu617a5d52014-11-13 10:56:20 -0500315 texture.maxAnisotropy = maxAnisotropy;
John Bauman89401822014-05-06 15:04:28 -0400316 }
317
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400318 void Sampler::setSwizzleR(SwizzleType swizzleR)
319 {
320 this->swizzleR = swizzleR;
321 }
Nicolas Capens7bb62682016-02-08 11:30:56 -0500322
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400323 void Sampler::setSwizzleG(SwizzleType swizzleG)
324 {
325 this->swizzleG = swizzleG;
326 }
327
328 void Sampler::setSwizzleB(SwizzleType swizzleB)
329 {
330 this->swizzleB = swizzleB;
331 }
332
333 void Sampler::setSwizzleA(SwizzleType swizzleA)
334 {
335 this->swizzleA = swizzleA;
336 }
337
John Bauman89401822014-05-06 15:04:28 -0400338 void Sampler::setFilterQuality(FilterType maximumFilterQuality)
339 {
340 Sampler::maximumTextureFilterQuality = maximumFilterQuality;
341 }
342
343 void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
344 {
345 Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
346 }
347
348 void Sampler::setMipmapLOD(float LOD)
349 {
350 texture.LOD = LOD;
351 exp2LOD = exp2(LOD);
352 }
353
354 bool Sampler::hasTexture() const
355 {
356 return textureType != TEXTURE_NULL;
357 }
358
359 bool Sampler::hasUnsignedTexture() const
360 {
361 return Surface::isUnsignedComponent(internalTextureFormat, 0) &&
362 Surface::isUnsignedComponent(internalTextureFormat, 1) &&
Nicolas Capens0bac2852016-05-07 06:09:58 -0400363 Surface::isUnsignedComponent(internalTextureFormat, 2) &&
364 Surface::isUnsignedComponent(internalTextureFormat, 3);
John Bauman89401822014-05-06 15:04:28 -0400365 }
366
367 bool Sampler::hasCubeTexture() const
368 {
369 return textureType == TEXTURE_CUBE;
370 }
371
372 bool Sampler::hasVolumeTexture() const
373 {
Alexis Hetuf15e8942015-12-01 15:13:23 -0500374 return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY;
John Bauman89401822014-05-06 15:04:28 -0400375 }
376
377 const Texture &Sampler::getTextureData()
378 {
379 return texture;
380 }
381
382 MipmapType Sampler::mipmapFilter() const
383 {
384 if(mipmapFilterState != MIPMAP_NONE)
385 {
386 for(int i = 1; i < MIPMAP_LEVELS; i++)
387 {
388 if(texture.mipmap[0].buffer[0] != texture.mipmap[i].buffer[0])
389 {
390 return mipmapFilterState;
391 }
392 }
393 }
394
395 // Only one mipmap level
396 return MIPMAP_NONE;
397 }
398
399 bool Sampler::hasNPOTTexture() const
400 {
401 if(textureType == TEXTURE_NULL)
402 {
403 return false;
404 }
405
Nicolas Capensadb305a2016-04-21 13:59:20 -0400406 for(int i = 0; i < MIPMAP_LEVELS; i++)
John Bauman19bac1e2014-05-06 15:23:49 -0400407 {
Nicolas Capensadb305a2016-04-21 13:59:20 -0400408 if(texture.mipmap[i].width[0] != texture.mipmap[i].onePitchP[1])
409 {
410 return true; // Shifting of the texture coordinates doesn't yield the correct address, so using multiply by pitch
411 }
John Bauman19bac1e2014-05-06 15:23:49 -0400412 }
413
John Bauman89401822014-05-06 15:04:28 -0400414 return !isPow2(texture.mipmap[0].width[0]) || !isPow2(texture.mipmap[0].height[0]) || !isPow2(texture.mipmap[0].depth[0]);
415 }
416
417 TextureType Sampler::getTextureType() const
418 {
419 return textureType;
420 }
421
422 FilterType Sampler::getTextureFilter() const
423 {
424 FilterType filter = textureFilter;
425
426 if(gather && Surface::componentCount(internalTextureFormat) == 1)
427 {
428 filter = FILTER_GATHER;
429 }
430
431 if(textureType != TEXTURE_2D || texture.maxAnisotropy == 1.0f)
432 {
433 return (FilterType)min(filter, FILTER_LINEAR);
434 }
435
436 return filter;
437 }
438
439 AddressingMode Sampler::getAddressingModeU() const
440 {
441 if(hasCubeTexture())
442 {
443 return ADDRESSING_CLAMP;
444 }
445
446 return addressingModeU;
447 }
448
449 AddressingMode Sampler::getAddressingModeV() const
450 {
451 if(hasCubeTexture())
452 {
453 return ADDRESSING_CLAMP;
454 }
455
456 return addressingModeV;
457 }
458
459 AddressingMode Sampler::getAddressingModeW() const
460 {
461 if(hasCubeTexture())
462 {
463 return ADDRESSING_CLAMP;
464 }
465
Nicolas Capens7bb62682016-02-08 11:30:56 -0500466 if(textureType == TEXTURE_2D_ARRAY || textureType == TEXTURE_2D)
467 {
468 return ADDRESSING_LAYER;
469 }
470
John Bauman89401822014-05-06 15:04:28 -0400471 return addressingModeW;
472 }
473}