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 "Shader/PixelRoutine.hpp" |
20 | #include "Common/Debug.hpp" |
21 | |
22 | #include <memory.h> |
23 | #include <string.h> |
24 | |
25 | namespace 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 |
38 | static const unsigned int zero = 0x00FF00FF; |
39 | |
40 | for(int level = 0; level < MIPMAP_LEVELS; level++) |
41 | { |
42 | Mipmap &mipmap = texture.mipmap[level]; |
43 | |
44 | memset(&mipmap, 0, sizeof(Mipmap)); |
45 | |
46 | for(int face = 0; face < 6; face++) |
47 | { |
48 | mipmap.buffer[face] = &zero; |
49 | } |
50 | } |
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; |
63 | highPrecisionFiltering = false; |
64 | border = 0; |
65 | |
66 | swizzleR = SWIZZLE_RED; |
67 | swizzleG = SWIZZLE_GREEN; |
68 | swizzleB = SWIZZLE_BLUE; |
69 | swizzleA = SWIZZLE_ALPHA; |
70 | |
71 | compare = COMPARE_BYPASS; |
72 | |
73 | texture.LOD = 0.0f; |
74 | exp2LOD = 1.0f; |
75 | |
76 | texture.baseLevel = 0; |
77 | texture.maxLevel = 1000; |
78 | texture.maxLod = MAX_TEXTURE_LOD; |
79 | texture.minLod = 0; |
80 | } |
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(); |
99 | state.sRGB = (sRGB && Surface::isSRGBreadable(externalTextureFormat)) || Surface::isSRGBformat(internalTextureFormat); |
100 | state.swizzleR = swizzleR; |
101 | state.swizzleG = swizzleG; |
102 | state.swizzleB = swizzleB; |
103 | state.swizzleA = swizzleA; |
104 | state.highPrecisionFiltering = highPrecisionFiltering; |
105 | state.compare = getCompareFunc(); |
106 | |
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 | border = surface->getBorder(); |
122 | mipmap.buffer[face] = surface->lockInternal(-border, -border, 0, LOCK_UNLOCKED, PRIVATE); |
123 | |
124 | if(face == 0) |
125 | { |
126 | externalTextureFormat = surface->getExternalFormat(); |
127 | internalTextureFormat = surface->getInternalFormat(); |
128 | |
129 | int width = surface->getWidth(); |
130 | int height = surface->getHeight(); |
131 | int depth = surface->getDepth(); |
132 | int pitchP = surface->getInternalPitchP(); |
133 | int sliceP = surface->getInternalSliceP(); |
134 | |
135 | 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 | |
158 | if(Surface::isFloatFormat(internalTextureFormat)) |
159 | { |
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 | |
176 | short halfTexelU = 0x8000 / width; |
177 | short halfTexelV = 0x8000 / height; |
178 | short halfTexelW = 0x8000 / depth; |
179 | |
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 | |
215 | mipmap.pitchP[0] = pitchP; |
216 | mipmap.pitchP[1] = pitchP; |
217 | mipmap.pitchP[2] = pitchP; |
218 | mipmap.pitchP[3] = pitchP; |
219 | |
220 | mipmap.sliceP[0] = sliceP; |
221 | mipmap.sliceP[1] = sliceP; |
222 | mipmap.sliceP[2] = sliceP; |
223 | mipmap.sliceP[3] = 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<16>(YStride / 2); |
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].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 | } |
250 | } |
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 | |
310 | void Sampler::setMaxAnisotropy(float maxAnisotropy) |
311 | { |
312 | texture.maxAnisotropy = maxAnisotropy; |
313 | } |
314 | |
315 | void Sampler::setHighPrecisionFiltering(bool highPrecisionFiltering) |
316 | { |
317 | this->highPrecisionFiltering = highPrecisionFiltering; |
318 | } |
319 | |
320 | void Sampler::setSwizzleR(SwizzleType swizzleR) |
321 | { |
322 | this->swizzleR = swizzleR; |
323 | } |
324 | |
325 | 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 | |
340 | void Sampler::setCompareFunc(CompareFunc compare) |
341 | { |
342 | this->compare = compare; |
343 | } |
344 | |
345 | 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 | |
355 | void Sampler::setMinLod(float minLod) |
356 | { |
357 | texture.minLod = clamp(minLod, 0.0f, (float)(MAX_TEXTURE_LOD)); |
358 | } |
359 | |
360 | void Sampler::setMaxLod(float maxLod) |
361 | { |
362 | texture.maxLod = clamp(maxLod, 0.0f, (float)(MAX_TEXTURE_LOD)); |
363 | } |
364 | |
365 | 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) && |
390 | Surface::isUnsignedComponent(internalTextureFormat, 2) && |
391 | Surface::isUnsignedComponent(internalTextureFormat, 3); |
392 | } |
393 | |
394 | bool Sampler::hasCubeTexture() const |
395 | { |
396 | return textureType == TEXTURE_CUBE; |
397 | } |
398 | |
399 | bool Sampler::hasVolumeTexture() const |
400 | { |
401 | return textureType == TEXTURE_3D || textureType == TEXTURE_2D_ARRAY; |
402 | } |
403 | |
404 | void Sampler::setSyncRequired(bool isSyncRequired) |
405 | { |
406 | syncRequired = isSyncRequired; |
407 | } |
408 | |
409 | bool Sampler::requiresSync() const |
410 | { |
411 | return syncRequired; |
412 | } |
413 | |
414 | 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 | |
436 | TextureType Sampler::getTextureType() const |
437 | { |
438 | return textureType; |
439 | } |
440 | |
441 | FilterType Sampler::getTextureFilter() const |
442 | { |
443 | // 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 | |
452 | 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 | { |
469 | if(textureType == TEXTURE_CUBE) |
470 | { |
471 | return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP; |
472 | } |
473 | |
474 | return addressingModeU; |
475 | } |
476 | |
477 | AddressingMode Sampler::getAddressingModeV() const |
478 | { |
479 | if(textureType == TEXTURE_CUBE) |
480 | { |
481 | return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP; |
482 | } |
483 | |
484 | return addressingModeV; |
485 | } |
486 | |
487 | AddressingMode Sampler::getAddressingModeW() const |
488 | { |
489 | if(textureType == TEXTURE_2D_ARRAY || |
490 | textureType == TEXTURE_2D || |
491 | textureType == TEXTURE_CUBE || |
492 | textureType == TEXTURE_RECTANGLE) |
493 | { |
494 | return ADDRESSING_LAYER; |
495 | } |
496 | |
497 | return addressingModeW; |
498 | } |
499 | |
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 | } |
514 | } |
515 | |