blob: 3b570ea95f20d3aac8dac17f35807475deb47a54 [file] [log] [blame]
Chia-I Wu28b89962014-08-18 14:40:49 +08001/*
2 * XGL
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu44e42362014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Chia-I Wu28b89962014-08-18 14:40:49 +080026 */
27
28#include "genhw/genhw.h"
29#include "dev.h"
30#include "sampler.h"
31
32/**
33 * Translate a pipe texture filter to the matching hardware mapfilter.
34 */
35static int translate_tex_filter(XGL_TEX_FILTER filter)
36{
37 switch (filter) {
38 case XGL_TEX_FILTER_NEAREST: return GEN6_MAPFILTER_NEAREST;
39 case XGL_TEX_FILTER_LINEAR: return GEN6_MAPFILTER_LINEAR;
40 default:
41 assert(!"unknown tex filter");
42 return GEN6_MAPFILTER_NEAREST;
43 }
44}
45
46static int translate_tex_mipmap_mode(XGL_TEX_MIPMAP_MODE mode)
47{
48 switch (mode) {
49 case XGL_TEX_MIPMAP_NEAREST: return GEN6_MIPFILTER_NEAREST;
50 case XGL_TEX_MIPMAP_LINEAR: return GEN6_MIPFILTER_LINEAR;
51 case XGL_TEX_MIPMAP_BASE: return GEN6_MIPFILTER_NONE;
52 default:
53 assert(!"unknown tex mipmap mode");
54 return GEN6_MIPFILTER_NONE;
55 }
56}
57
58static int translate_tex_addr(XGL_TEX_ADDRESS addr)
59{
60 switch (addr) {
61 case XGL_TEX_ADDRESS_WRAP: return GEN6_TEXCOORDMODE_WRAP;
62 case XGL_TEX_ADDRESS_MIRROR: return GEN6_TEXCOORDMODE_MIRROR;
63 case XGL_TEX_ADDRESS_CLAMP: return GEN6_TEXCOORDMODE_CLAMP;
64 case XGL_TEX_ADDRESS_MIRROR_ONCE: return GEN6_TEXCOORDMODE_MIRROR_ONCE;
65 case XGL_TEX_ADDRESS_CLAMP_BORDER: return GEN6_TEXCOORDMODE_CLAMP_BORDER;
66 default:
67 assert(!"unknown tex address");
68 return GEN6_TEXCOORDMODE_WRAP;
69 }
70}
71
72static int translate_compare_func(XGL_COMPARE_FUNC func)
73{
74 switch (func) {
75 case XGL_COMPARE_NEVER: return GEN6_COMPAREFUNCTION_NEVER;
76 case XGL_COMPARE_LESS: return GEN6_COMPAREFUNCTION_LESS;
77 case XGL_COMPARE_EQUAL: return GEN6_COMPAREFUNCTION_EQUAL;
78 case XGL_COMPARE_LESS_EQUAL: return GEN6_COMPAREFUNCTION_LEQUAL;
79 case XGL_COMPARE_GREATER: return GEN6_COMPAREFUNCTION_GREATER;
80 case XGL_COMPARE_NOT_EQUAL: return GEN6_COMPAREFUNCTION_NOTEQUAL;
81 case XGL_COMPARE_GREATER_EQUAL: return GEN6_COMPAREFUNCTION_GEQUAL;
82 case XGL_COMPARE_ALWAYS: return GEN6_COMPAREFUNCTION_ALWAYS;
83 default:
84 assert(!"unknown compare_func");
85 return GEN6_COMPAREFUNCTION_NEVER;
86 }
87}
88
89static void translate_border_color(XGL_BORDER_COLOR_TYPE type, float rgba[4])
90{
91 switch (type) {
92 case XGL_BORDER_COLOR_OPAQUE_WHITE:
93 rgba[0] = 1.0;
94 rgba[1] = 1.0;
95 rgba[2] = 1.0;
96 rgba[3] = 1.0;
97 break;
98 case XGL_BORDER_COLOR_TRANSPARENT_BLACK:
99 default:
100 rgba[0] = 0.0;
101 rgba[1] = 0.0;
102 rgba[2] = 0.0;
103 rgba[3] = 0.0;
104 break;
105 case XGL_BORDER_COLOR_OPAQUE_BLACK:
106 rgba[0] = 0.0;
107 rgba[1] = 0.0;
108 rgba[2] = 0.0;
109 rgba[3] = 1.0;
110 break;
111 }
112}
113
114static void
Chia-I Wu06bed192014-08-20 13:57:18 +0800115sampler_border_color_state_gen6(const struct intel_gpu *gpu,
116 const float color[4],
117 uint32_t dw[12])
Chia-I Wu28b89962014-08-18 14:40:49 +0800118{
119 float rgba[4] = { color[0], color[1], color[2], color[3] };
120
121 INTEL_GPU_ASSERT(gpu, 6, 6);
122
123 /*
124 * This state is not documented in the Sandy Bridge PRM, but in the
125 * Ironlake PRM. SNORM8 seems to be in DW11 instead of DW1.
126 */
127
128 /* IEEE_FP */
129 dw[1] = u_fui(rgba[0]);
130 dw[2] = u_fui(rgba[1]);
131 dw[3] = u_fui(rgba[2]);
132 dw[4] = u_fui(rgba[3]);
133
134 /* FLOAT_16 */
135 dw[5] = u_float_to_half(rgba[0]) |
136 u_float_to_half(rgba[1]) << 16;
137 dw[6] = u_float_to_half(rgba[2]) |
138 u_float_to_half(rgba[3]) << 16;
139
140 /* clamp to [-1.0f, 1.0f] */
141 rgba[0] = U_CLAMP(rgba[0], -1.0f, 1.0f);
142 rgba[1] = U_CLAMP(rgba[1], -1.0f, 1.0f);
143 rgba[2] = U_CLAMP(rgba[2], -1.0f, 1.0f);
144 rgba[3] = U_CLAMP(rgba[3], -1.0f, 1.0f);
145
146 /* SNORM16 */
147 dw[9] = (int16_t) u_iround(rgba[0] * 32767.0f) |
148 (int16_t) u_iround(rgba[1] * 32767.0f) << 16;
149 dw[10] = (int16_t) u_iround(rgba[2] * 32767.0f) |
150 (int16_t) u_iround(rgba[3] * 32767.0f) << 16;
151
152 /* SNORM8 */
153 dw[11] = (int8_t) u_iround(rgba[0] * 127.0f) |
154 (int8_t) u_iround(rgba[1] * 127.0f) << 8 |
155 (int8_t) u_iround(rgba[2] * 127.0f) << 16 |
156 (int8_t) u_iround(rgba[3] * 127.0f) << 24;
157
158 /* clamp to [0.0f, 1.0f] */
159 rgba[0] = U_CLAMP(rgba[0], 0.0f, 1.0f);
160 rgba[1] = U_CLAMP(rgba[1], 0.0f, 1.0f);
161 rgba[2] = U_CLAMP(rgba[2], 0.0f, 1.0f);
162 rgba[3] = U_CLAMP(rgba[3], 0.0f, 1.0f);
163
164 /* UNORM8 */
165 dw[0] = (uint8_t) u_iround(rgba[0] * 255.0f) |
166 (uint8_t) u_iround(rgba[1] * 255.0f) << 8 |
167 (uint8_t) u_iround(rgba[2] * 255.0f) << 16 |
168 (uint8_t) u_iround(rgba[3] * 255.0f) << 24;
169
170 /* UNORM16 */
171 dw[7] = (uint16_t) u_iround(rgba[0] * 65535.0f) |
172 (uint16_t) u_iround(rgba[1] * 65535.0f) << 16;
173 dw[8] = (uint16_t) u_iround(rgba[2] * 65535.0f) |
174 (uint16_t) u_iround(rgba[3] * 65535.0f) << 16;
175}
176
177static void
Chia-I Wu375d0992014-08-18 23:38:23 +0800178sampler_init(struct intel_sampler *sampler,
179 const struct intel_gpu *gpu,
180 const XGL_SAMPLER_CREATE_INFO *info)
Chia-I Wu28b89962014-08-18 14:40:49 +0800181{
182 int mip_filter, min_filter, mag_filter, max_aniso;
183 int lod_bias, max_lod, min_lod;
184 int wrap_s, wrap_t, wrap_r;
185 uint32_t dw0, dw1, dw3;
186 float border_color[4];
187
188 INTEL_GPU_ASSERT(gpu, 6, 7.5);
Chia-I Wu375d0992014-08-18 23:38:23 +0800189 STATIC_ASSERT(ARRAY_SIZE(sampler->cmd) >= 15);
Chia-I Wu28b89962014-08-18 14:40:49 +0800190
191 mip_filter = translate_tex_mipmap_mode(info->mipMode);
192 min_filter = translate_tex_filter(info->minFilter);
193 mag_filter = translate_tex_filter(info->magFilter);
194
195 if (info->maxAnisotropy >= 2 && info->maxAnisotropy <= 16)
196 max_aniso = info->maxAnisotropy / 2 - 1;
197 else if (info->maxAnisotropy > 16)
198 max_aniso = GEN6_ANISORATIO_16;
199 else
200 max_aniso = GEN6_ANISORATIO_2;
201
202 /*
203 * Here is how the hardware calculate per-pixel LOD, from my reading of the
204 * PRMs:
205 *
206 * 1) LOD is set to log2(ratio of texels to pixels) if not specified in
207 * other ways. The number of texels is measured using level
208 * SurfMinLod.
209 * 2) Bias is added to LOD.
210 * 3) LOD is clamped to [MinLod, MaxLod], and the clamped value is
211 * compared with Base to determine whether magnification or
212 * minification is needed. (if preclamp is disabled, LOD is compared
213 * with Base before clamping)
214 * 4) If magnification is needed, or no mipmapping is requested, LOD is
215 * set to floor(MinLod).
216 * 5) LOD is clamped to [0, MIPCnt], and SurfMinLod is added to LOD.
217 *
218 * With Gallium interface, Base is always zero and
219 * pipe_sampler_view::u.tex.first_level specifies SurfMinLod.
220 */
221 if (intel_gpu_gen(gpu) >= INTEL_GEN(7)) {
222 const float scale = 256.0f;
223
224 /* [-16.0, 16.0) in S4.8 */
225 lod_bias = (int)
226 (U_CLAMP(info->mipLodBias, -16.0f, 15.9f) * scale);
227 lod_bias &= 0x1fff;
228
229 /* [0.0, 14.0] in U4.8 */
230 max_lod = (int) (U_CLAMP(info->maxLod, 0.0f, 14.0f) * scale);
231 min_lod = (int) (U_CLAMP(info->minLod, 0.0f, 14.0f) * scale);
232 }
233 else {
234 const float scale = 64.0f;
235
236 /* [-16.0, 16.0) in S4.6 */
237 lod_bias = (int)
238 (U_CLAMP(info->mipLodBias, -16.0f, 15.9f) * scale);
239 lod_bias &= 0x7ff;
240
241 /* [0.0, 13.0] in U4.6 */
242 max_lod = (int) (U_CLAMP(info->maxLod, 0.0f, 13.0f) * scale);
243 min_lod = (int) (U_CLAMP(info->minLod, 0.0f, 13.0f) * scale);
244 }
245
246 /*
247 * We want LOD to be clamped to determine magnification/minification, and
248 * get set to zero when it is magnification or when mipmapping is disabled.
249 * The hardware would set LOD to floor(MinLod) and that is a problem when
250 * MinLod is greater than or equal to 1.0f.
251 *
252 * With Base being zero, it is always minification when MinLod is non-zero.
253 * To achieve our goal, we just need to set MinLod to zero and set
254 * MagFilter to MinFilter when mipmapping is disabled.
255 */
256 if (info->mipMode == XGL_TEX_MIPMAP_BASE && min_lod) {
257 min_lod = 0;
258 mag_filter = min_filter;
259 }
260
261 /* determine wrap s/t/r */
262 wrap_s = translate_tex_addr(info->addressU);
263 wrap_t = translate_tex_addr(info->addressV);
264 wrap_r = translate_tex_addr(info->addressW);
265
266 translate_border_color(info->borderColorType, border_color);
267
268 if (intel_gpu_gen(gpu) >= INTEL_GEN(7)) {
269 dw0 = 1 << 28 |
270 mip_filter << 20 |
271 lod_bias << 1;
272
273 if (info->maxAnisotropy) {
274 dw0 |= GEN6_MAPFILTER_ANISOTROPIC << 17 |
275 GEN6_MAPFILTER_ANISOTROPIC << 14 |
276 1;
277 } else {
278 dw0 |= mag_filter << 17 |
279 min_filter << 14;
280 }
281
282 dw1 = min_lod << 20 |
283 max_lod << 8;
284
285 dw1 |= translate_compare_func(info->compareFunc) << 1;
286
287 dw3 = max_aniso << 19;
288
289 /* round the coordinates for linear filtering */
290 if (min_filter != GEN6_MAPFILTER_NEAREST) {
291 dw3 |= (GEN6_SAMPLER_DW3_U_MIN_ROUND |
292 GEN6_SAMPLER_DW3_V_MIN_ROUND |
293 GEN6_SAMPLER_DW3_R_MIN_ROUND);
294 }
295 if (mag_filter != GEN6_MAPFILTER_NEAREST) {
296 dw3 |= (GEN6_SAMPLER_DW3_U_MAG_ROUND |
297 GEN6_SAMPLER_DW3_V_MAG_ROUND |
298 GEN6_SAMPLER_DW3_R_MAG_ROUND);
299 }
300
301 dw3 |= wrap_s << 6 |
302 wrap_t << 3 |
303 wrap_r;
304
Chia-I Wu375d0992014-08-18 23:38:23 +0800305 sampler->cmd[0] = dw0;
306 sampler->cmd[1] = dw1;
307 sampler->cmd[2] = dw3;
Chia-I Wu28b89962014-08-18 14:40:49 +0800308
Chia-I Wu375d0992014-08-18 23:38:23 +0800309 memcpy(&sampler->cmd[3], &border_color, sizeof(border_color));
Chia-I Wu28b89962014-08-18 14:40:49 +0800310 }
311 else {
312 dw0 = 1 << 28 |
313 mip_filter << 20 |
314 lod_bias << 3;
315
316 dw0 |= translate_compare_func(info->compareFunc);
317
318 if (info->maxAnisotropy) {
319 dw0 |= GEN6_MAPFILTER_ANISOTROPIC << 17 |
320 GEN6_MAPFILTER_ANISOTROPIC << 14;
321 }
322 else {
323 dw0 |= (min_filter != mag_filter) << 27 |
324 mag_filter << 17 |
325 min_filter << 14;
326 }
327
328 dw1 = min_lod << 22 |
329 max_lod << 12;
330
331 dw1 |= wrap_s << 6 |
332 wrap_t << 3 |
333 wrap_r;
334
335 dw3 = max_aniso << 19;
336
337 /* round the coordinates for linear filtering */
338 if (min_filter != GEN6_MAPFILTER_NEAREST) {
339 dw3 |= (GEN6_SAMPLER_DW3_U_MIN_ROUND |
340 GEN6_SAMPLER_DW3_V_MIN_ROUND |
341 GEN6_SAMPLER_DW3_R_MIN_ROUND);
342 }
343 if (mag_filter != GEN6_MAPFILTER_NEAREST) {
344 dw3 |= (GEN6_SAMPLER_DW3_U_MAG_ROUND |
345 GEN6_SAMPLER_DW3_V_MAG_ROUND |
346 GEN6_SAMPLER_DW3_R_MAG_ROUND);
347 }
348
Chia-I Wu375d0992014-08-18 23:38:23 +0800349 sampler->cmd[0] = dw0;
350 sampler->cmd[1] = dw1;
351 sampler->cmd[2] = dw3;
Chia-I Wu28b89962014-08-18 14:40:49 +0800352
Chia-I Wu06bed192014-08-20 13:57:18 +0800353 sampler_border_color_state_gen6(gpu, border_color, &sampler->cmd[3]);
Chia-I Wu28b89962014-08-18 14:40:49 +0800354 }
355}
356
357static void sampler_destroy(struct intel_obj *obj)
358{
359 struct intel_sampler *sampler = intel_sampler_from_obj(obj);
360
361 intel_sampler_destroy(sampler);
362}
363
364XGL_RESULT intel_sampler_create(struct intel_dev *dev,
365 const XGL_SAMPLER_CREATE_INFO *info,
366 struct intel_sampler **sampler_ret)
367{
368 struct intel_sampler *sampler;
369
370 sampler = (struct intel_sampler *) intel_base_create(dev,
371 sizeof(*sampler), dev->base.dbg, XGL_DBG_OBJECT_SAMPLER, info, 0);
372 if (!sampler)
373 return XGL_ERROR_OUT_OF_MEMORY;
374
375 sampler->obj.destroy = sampler_destroy;
376
Chia-I Wu375d0992014-08-18 23:38:23 +0800377 sampler_init(sampler, dev->gpu, info);
Chia-I Wu28b89962014-08-18 14:40:49 +0800378
379 *sampler_ret = sampler;
380
381 return XGL_SUCCESS;
382}
383
384void intel_sampler_destroy(struct intel_sampler *sampler)
385{
386 intel_base_destroy(&sampler->obj.base);
387}
388
389XGL_RESULT XGLAPI intelCreateSampler(
390 XGL_DEVICE device,
391 const XGL_SAMPLER_CREATE_INFO* pCreateInfo,
392 XGL_SAMPLER* pSampler)
393{
394 struct intel_dev *dev = intel_dev(device);
395
396 return intel_sampler_create(dev, pCreateInfo,
397 (struct intel_sampler **) pSampler);
398}