blob: f4d5061b387509cebd004eef5c2483265898c956 [file] [log] [blame]
John Bauman89401822014-05-06 15:04:28 -04001// SwiftShader Software Renderer
2//
John Bauman19bac1e2014-05-06 15:23:49 -04003// Copyright(c) 2005-2012 TransGaming Inc.
John Bauman89401822014-05-06 15:04:28 -04004//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "Sampler.hpp"
13
14#include "MetaMacro.hpp"
15#include "Context.hpp"
16#include "Surface.hpp"
17#include "CPUID.hpp"
18#include "PixelRoutine.hpp"
19#include "Debug.hpp"
20
21#include <memory.h>
22#include <string.h>
23
24namespace sw
25{
26 FilterType Sampler::maximumTextureFilterQuality = FILTER_LINEAR;
27 MipmapType Sampler::maximumMipmapFilterQuality = MIPMAP_POINT;
28
29 Sampler::State::State()
30 {
31 memset(this, 0, sizeof(State));
32 }
33
34 Sampler::Sampler()
35 {
36 // FIXME: Mipmap::init
Nicolas Capens8e8a7e82015-09-01 14:39:57 -040037 static const unsigned int zero = 0x00FF00FF;
John Bauman89401822014-05-06 15:04:28 -040038
39 for(int level = 0; level < MIPMAP_LEVELS; level++)
40 {
41 Mipmap &mipmap = texture.mipmap[level];
42
43 memset(&mipmap, 0, sizeof(Mipmap));
44
45 for(int face = 0; face < 6; face++)
46 {
47 mipmap.buffer[face] = &zero;
48 }
49
50 mipmap.uFrac = 16;
51 mipmap.vFrac = 16;
52 mipmap.wFrac = 16;
53 }
54
55 externalTextureFormat = FORMAT_NULL;
56 internalTextureFormat = FORMAT_NULL;
57 textureType = TEXTURE_NULL;
58
59 textureFilter = FILTER_LINEAR;
60 addressingModeU = ADDRESSING_WRAP;
61 addressingModeV = ADDRESSING_WRAP;
62 addressingModeW = ADDRESSING_WRAP;
63 mipmapFilterState = MIPMAP_NONE;
64 sRGB = false;
65 gather = false;
66
67 texture.LOD = 0.0f;
68 exp2LOD = 1.0f;
69 }
70
71 Sampler::~Sampler()
72 {
73 }
74
75 Sampler::State Sampler::samplerState() const
76 {
77 State state;
78
79 if(textureType != TEXTURE_NULL)
80 {
81 state.textureType = textureType;
82 state.textureFormat = internalTextureFormat;
83 state.textureFilter = getTextureFilter();
84 state.addressingModeU = getAddressingModeU();
85 state.addressingModeV = getAddressingModeV();
86 state.addressingModeW = getAddressingModeW();
87 state.mipmapFilter = mipmapFilter();
88 state.hasNPOTTexture = hasNPOTTexture();
89 state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat);
90
91 #if PERF_PROFILE
92 state.compressedFormat = Surface::isCompressed(externalTextureFormat);
93 #endif
94 }
95
96 return state;
97 }
98
99 void Sampler::setTextureLevel(int face, int level, Surface *surface, TextureType type)
100 {
101 if(surface)
102 {
103 Mipmap &mipmap = texture.mipmap[level];
104
105 mipmap.buffer[face] = surface->lockInternal(0, 0, 0, LOCK_UNLOCKED, PRIVATE);
106
107 if(face == 0)
108 {
109 externalTextureFormat = surface->getExternalFormat();
110 internalTextureFormat = surface->getInternalFormat();
111
Nicolas Capens3779ea92015-06-10 13:43:52 -0400112 int width = surface->getWidth();
113 int height = surface->getHeight();
114 int depth = surface->getDepth();
John Bauman89401822014-05-06 15:04:28 -0400115 int pitchP = surface->getInternalPitchP();
116 int sliceP = surface->getInternalSliceP();
117
118 int logWidth = log2(width);
119 int logHeight = log2(height);
120 int logDepth = log2(depth);
121
122 if(level == 0)
123 {
124 texture.widthHeightLOD[0] = width * exp2LOD;
125 texture.widthHeightLOD[1] = width * exp2LOD;
126 texture.widthHeightLOD[2] = height * exp2LOD;
127 texture.widthHeightLOD[3] = height * exp2LOD;
128
129 texture.widthLOD[0] = width * exp2LOD;
130 texture.widthLOD[1] = width * exp2LOD;
131 texture.widthLOD[2] = width * exp2LOD;
132 texture.widthLOD[3] = width * exp2LOD;
133
134 texture.heightLOD[0] = height * exp2LOD;
135 texture.heightLOD[1] = height * exp2LOD;
136 texture.heightLOD[2] = height * exp2LOD;
137 texture.heightLOD[3] = height * exp2LOD;
138
139 texture.depthLOD[0] = depth * exp2LOD;
140 texture.depthLOD[1] = depth * exp2LOD;
141 texture.depthLOD[2] = depth * exp2LOD;
142 texture.depthLOD[3] = depth * exp2LOD;
143 }
144
145 if(!Surface::isFloatFormat(internalTextureFormat))
146 {
147 mipmap.uInt = logWidth;
148 mipmap.vInt = logHeight;
149 mipmap.wInt = logDepth;
150 mipmap.uFrac = 16 - logWidth;
151 mipmap.vFrac = 16 - logHeight;
152 mipmap.wFrac = 16 - logDepth;
153 }
154 else
155 {
156 mipmap.fWidth[0] = (float)width / 65536.0f;
157 mipmap.fWidth[1] = (float)width / 65536.0f;
158 mipmap.fWidth[2] = (float)width / 65536.0f;
159 mipmap.fWidth[3] = (float)width / 65536.0f;
160
161 mipmap.fHeight[0] = (float)height / 65536.0f;
162 mipmap.fHeight[1] = (float)height / 65536.0f;
163 mipmap.fHeight[2] = (float)height / 65536.0f;
164 mipmap.fHeight[3] = (float)height / 65536.0f;
165
166 mipmap.fDepth[0] = (float)depth / 65536.0f;
167 mipmap.fDepth[1] = (float)depth / 65536.0f;
168 mipmap.fDepth[2] = (float)depth / 65536.0f;
169 mipmap.fDepth[3] = (float)depth / 65536.0f;
170 }
171
172 short halfTexelU = isPow2(width) ? 0x8000 >> logWidth : 0x8000 / width;
173 short halfTexelV = isPow2(height) ? 0x8000 >> logHeight : 0x8000 / height;
174 short halfTexelW = isPow2(depth) ? 0x8000 >> logDepth : 0x8000 / depth;
175
176 mipmap.uHalf[0] = halfTexelU;
177 mipmap.uHalf[1] = halfTexelU;
178 mipmap.uHalf[2] = halfTexelU;
179 mipmap.uHalf[3] = halfTexelU;
180
181 mipmap.vHalf[0] = halfTexelV;
182 mipmap.vHalf[1] = halfTexelV;
183 mipmap.vHalf[2] = halfTexelV;
184 mipmap.vHalf[3] = halfTexelV;
185
186 mipmap.wHalf[0] = halfTexelW;
187 mipmap.wHalf[1] = halfTexelW;
188 mipmap.wHalf[2] = halfTexelW;
189 mipmap.wHalf[3] = halfTexelW;
190
191 mipmap.width[0] = width;
192 mipmap.width[1] = width;
193 mipmap.width[2] = width;
194 mipmap.width[3] = width;
195
196 mipmap.height[0] = height;
197 mipmap.height[1] = height;
198 mipmap.height[2] = height;
199 mipmap.height[3] = height;
200
201 mipmap.depth[0] = depth;
202 mipmap.depth[1] = depth;
203 mipmap.depth[2] = depth;
204 mipmap.depth[3] = depth;
205
206 mipmap.onePitchP[0] = 1;
207 mipmap.onePitchP[1] = pitchP;
208 mipmap.onePitchP[2] = 1;
209 mipmap.onePitchP[3] = pitchP;
210
211 mipmap.sliceP[0] = sliceP;
212 mipmap.sliceP[1] = sliceP;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400213
214 if(internalTextureFormat == FORMAT_YV12_BT601 ||
215 internalTextureFormat == FORMAT_YV12_BT709 ||
216 internalTextureFormat == FORMAT_YV12_JFIF)
217 {
218 unsigned int YStride = align(width, 16);
219 unsigned int YSize = YStride * height;
220 unsigned int CStride = align(YStride / 2, 16);
221 unsigned int CSize = CStride * height / 2;
222
223 mipmap.buffer[1] = (byte*)mipmap.buffer[0] + YSize;
224 mipmap.buffer[2] = (byte*)mipmap.buffer[1] + CSize;
225
226 texture.mipmap[1].uFrac = texture.mipmap[0].uFrac + 1;
227 texture.mipmap[1].vFrac = texture.mipmap[0].vFrac + 1;
228 texture.mipmap[1].width[0] = width / 2;
229 texture.mipmap[1].width[1] = width / 2;
230 texture.mipmap[1].width[2] = width / 2;
231 texture.mipmap[1].width[3] = width / 2;
232 texture.mipmap[1].height[0] = height / 2;
233 texture.mipmap[1].height[1] = height / 2;
234 texture.mipmap[1].height[2] = height / 2;
235 texture.mipmap[1].height[3] = height / 2;
236 texture.mipmap[1].onePitchP[0] = 1;
237 texture.mipmap[1].onePitchP[1] = CStride;
238 texture.mipmap[1].onePitchP[2] = 1;
239 texture.mipmap[1].onePitchP[3] = CStride;
240 }
John Bauman89401822014-05-06 15:04:28 -0400241 }
242 }
243
244 textureType = type;
245 }
246
247 void Sampler::setTextureFilter(FilterType textureFilter)
248 {
249 this->textureFilter = (FilterType)min(textureFilter, maximumTextureFilterQuality);
250 }
251
252 void Sampler::setMipmapFilter(MipmapType mipmapFilter)
253 {
254 mipmapFilterState = (MipmapType)min(mipmapFilter, maximumMipmapFilterQuality);
255 }
256
257 void Sampler::setGatherEnable(bool enable)
258 {
259 gather = enable;
260 }
261
262 void Sampler::setAddressingModeU(AddressingMode addressingMode)
263 {
264 addressingModeU = addressingMode;
265 }
266
267 void Sampler::setAddressingModeV(AddressingMode addressingMode)
268 {
269 addressingModeV = addressingMode;
270 }
271
272 void Sampler::setAddressingModeW(AddressingMode addressingMode)
273 {
274 addressingModeW = addressingMode;
275 }
276
277 void Sampler::setReadSRGB(bool sRGB)
278 {
279 this->sRGB = sRGB;
280 }
281
282 void Sampler::setBorderColor(const Color<float> &borderColor)
283 {
284 // FIXME: Compact into generic function // FIXME: Clamp
285 short r = iround(0xFFFF * borderColor.r);
286 short g = iround(0xFFFF * borderColor.g);
287 short b = iround(0xFFFF * borderColor.b);
288 short a = iround(0xFFFF * borderColor.a);
289
290 texture.borderColor4[0][0] = texture.borderColor4[0][1] = texture.borderColor4[0][2] = texture.borderColor4[0][3] = r;
291 texture.borderColor4[1][0] = texture.borderColor4[1][1] = texture.borderColor4[1][2] = texture.borderColor4[1][3] = g;
292 texture.borderColor4[2][0] = texture.borderColor4[2][1] = texture.borderColor4[2][2] = texture.borderColor4[2][3] = b;
293 texture.borderColor4[3][0] = texture.borderColor4[3][1] = texture.borderColor4[3][2] = texture.borderColor4[3][3] = a;
294
295 texture.borderColorF[0][0] = texture.borderColorF[0][1] = texture.borderColorF[0][2] = texture.borderColorF[0][3] = borderColor.r;
296 texture.borderColorF[1][0] = texture.borderColorF[1][1] = texture.borderColorF[1][2] = texture.borderColorF[1][3] = borderColor.g;
297 texture.borderColorF[2][0] = texture.borderColorF[2][1] = texture.borderColorF[2][2] = texture.borderColorF[2][3] = borderColor.b;
298 texture.borderColorF[3][0] = texture.borderColorF[3][1] = texture.borderColorF[3][2] = texture.borderColorF[3][3] = borderColor.a;
299 }
300
Alexis Hetu617a5d52014-11-13 10:56:20 -0500301 void Sampler::setMaxAnisotropy(float maxAnisotropy)
John Bauman89401822014-05-06 15:04:28 -0400302 {
Alexis Hetu617a5d52014-11-13 10:56:20 -0500303 texture.maxAnisotropy = maxAnisotropy;
John Bauman89401822014-05-06 15:04:28 -0400304 }
305
306 void Sampler::setFilterQuality(FilterType maximumFilterQuality)
307 {
308 Sampler::maximumTextureFilterQuality = maximumFilterQuality;
309 }
310
311 void Sampler::setMipmapQuality(MipmapType maximumFilterQuality)
312 {
313 Sampler::maximumMipmapFilterQuality = maximumFilterQuality;
314 }
315
316 void Sampler::setMipmapLOD(float LOD)
317 {
318 texture.LOD = LOD;
319 exp2LOD = exp2(LOD);
320 }
321
322 bool Sampler::hasTexture() const
323 {
324 return textureType != TEXTURE_NULL;
325 }
326
327 bool Sampler::hasUnsignedTexture() const
328 {
329 return Surface::isUnsignedComponent(internalTextureFormat, 0) &&
330 Surface::isUnsignedComponent(internalTextureFormat, 1) &&
331 Surface::isUnsignedComponent(internalTextureFormat, 2) &&
332 Surface::isUnsignedComponent(internalTextureFormat, 3);
333 }
334
335 bool Sampler::hasCubeTexture() const
336 {
337 return textureType == TEXTURE_CUBE;
338 }
339
340 bool Sampler::hasVolumeTexture() const
341 {
342 return textureType == TEXTURE_3D;
343 }
344
345 const Texture &Sampler::getTextureData()
346 {
347 return texture;
348 }
349
350 MipmapType Sampler::mipmapFilter() const
351 {
352 if(mipmapFilterState != MIPMAP_NONE)
353 {
354 for(int i = 1; i < MIPMAP_LEVELS; i++)
355 {
356 if(texture.mipmap[0].buffer[0] != texture.mipmap[i].buffer[0])
357 {
358 return mipmapFilterState;
359 }
360 }
361 }
362
363 // Only one mipmap level
364 return MIPMAP_NONE;
365 }
366
367 bool Sampler::hasNPOTTexture() const
368 {
369 if(textureType == TEXTURE_NULL)
370 {
371 return false;
372 }
373
John Bauman19bac1e2014-05-06 15:23:49 -0400374 if(texture.mipmap[0].width[0] != texture.mipmap[0].onePitchP[1])
375 {
376 return true; // Shifting of the texture coordinates doesn't yield the correct address, so using multiply by pitch
377 }
378
John Bauman89401822014-05-06 15:04:28 -0400379 return !isPow2(texture.mipmap[0].width[0]) || !isPow2(texture.mipmap[0].height[0]) || !isPow2(texture.mipmap[0].depth[0]);
380 }
381
382 TextureType Sampler::getTextureType() const
383 {
384 return textureType;
385 }
386
387 FilterType Sampler::getTextureFilter() const
388 {
389 FilterType filter = textureFilter;
390
391 if(gather && Surface::componentCount(internalTextureFormat) == 1)
392 {
393 filter = FILTER_GATHER;
394 }
395
396 if(textureType != TEXTURE_2D || texture.maxAnisotropy == 1.0f)
397 {
398 return (FilterType)min(filter, FILTER_LINEAR);
399 }
400
401 return filter;
402 }
403
404 AddressingMode Sampler::getAddressingModeU() const
405 {
406 if(hasCubeTexture())
407 {
408 return ADDRESSING_CLAMP;
409 }
410
411 return addressingModeU;
412 }
413
414 AddressingMode Sampler::getAddressingModeV() const
415 {
416 if(hasCubeTexture())
417 {
418 return ADDRESSING_CLAMP;
419 }
420
421 return addressingModeV;
422 }
423
424 AddressingMode Sampler::getAddressingModeW() const
425 {
426 if(hasCubeTexture())
427 {
428 return ADDRESSING_CLAMP;
429 }
430
431 return addressingModeW;
432 }
433}