blob: 6c6011a02cf7dd091cf9ac256336171db868ffb0 [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.
23 */
24
25#include "genhw/genhw.h"
26#include "dev.h"
27#include "sampler.h"
28
29/**
30 * Translate a pipe texture filter to the matching hardware mapfilter.
31 */
32static int translate_tex_filter(XGL_TEX_FILTER filter)
33{
34 switch (filter) {
35 case XGL_TEX_FILTER_NEAREST: return GEN6_MAPFILTER_NEAREST;
36 case XGL_TEX_FILTER_LINEAR: return GEN6_MAPFILTER_LINEAR;
37 default:
38 assert(!"unknown tex filter");
39 return GEN6_MAPFILTER_NEAREST;
40 }
41}
42
43static int translate_tex_mipmap_mode(XGL_TEX_MIPMAP_MODE mode)
44{
45 switch (mode) {
46 case XGL_TEX_MIPMAP_NEAREST: return GEN6_MIPFILTER_NEAREST;
47 case XGL_TEX_MIPMAP_LINEAR: return GEN6_MIPFILTER_LINEAR;
48 case XGL_TEX_MIPMAP_BASE: return GEN6_MIPFILTER_NONE;
49 default:
50 assert(!"unknown tex mipmap mode");
51 return GEN6_MIPFILTER_NONE;
52 }
53}
54
55static int translate_tex_addr(XGL_TEX_ADDRESS addr)
56{
57 switch (addr) {
58 case XGL_TEX_ADDRESS_WRAP: return GEN6_TEXCOORDMODE_WRAP;
59 case XGL_TEX_ADDRESS_MIRROR: return GEN6_TEXCOORDMODE_MIRROR;
60 case XGL_TEX_ADDRESS_CLAMP: return GEN6_TEXCOORDMODE_CLAMP;
61 case XGL_TEX_ADDRESS_MIRROR_ONCE: return GEN6_TEXCOORDMODE_MIRROR_ONCE;
62 case XGL_TEX_ADDRESS_CLAMP_BORDER: return GEN6_TEXCOORDMODE_CLAMP_BORDER;
63 default:
64 assert(!"unknown tex address");
65 return GEN6_TEXCOORDMODE_WRAP;
66 }
67}
68
69static int translate_compare_func(XGL_COMPARE_FUNC func)
70{
71 switch (func) {
72 case XGL_COMPARE_NEVER: return GEN6_COMPAREFUNCTION_NEVER;
73 case XGL_COMPARE_LESS: return GEN6_COMPAREFUNCTION_LESS;
74 case XGL_COMPARE_EQUAL: return GEN6_COMPAREFUNCTION_EQUAL;
75 case XGL_COMPARE_LESS_EQUAL: return GEN6_COMPAREFUNCTION_LEQUAL;
76 case XGL_COMPARE_GREATER: return GEN6_COMPAREFUNCTION_GREATER;
77 case XGL_COMPARE_NOT_EQUAL: return GEN6_COMPAREFUNCTION_NOTEQUAL;
78 case XGL_COMPARE_GREATER_EQUAL: return GEN6_COMPAREFUNCTION_GEQUAL;
79 case XGL_COMPARE_ALWAYS: return GEN6_COMPAREFUNCTION_ALWAYS;
80 default:
81 assert(!"unknown compare_func");
82 return GEN6_COMPAREFUNCTION_NEVER;
83 }
84}
85
86static void translate_border_color(XGL_BORDER_COLOR_TYPE type, float rgba[4])
87{
88 switch (type) {
89 case XGL_BORDER_COLOR_OPAQUE_WHITE:
90 rgba[0] = 1.0;
91 rgba[1] = 1.0;
92 rgba[2] = 1.0;
93 rgba[3] = 1.0;
94 break;
95 case XGL_BORDER_COLOR_TRANSPARENT_BLACK:
96 default:
97 rgba[0] = 0.0;
98 rgba[1] = 0.0;
99 rgba[2] = 0.0;
100 rgba[3] = 0.0;
101 break;
102 case XGL_BORDER_COLOR_OPAQUE_BLACK:
103 rgba[0] = 0.0;
104 rgba[1] = 0.0;
105 rgba[2] = 0.0;
106 rgba[3] = 1.0;
107 break;
108 }
109}
110
111static void
112emit_border_color_gen6(const struct intel_gpu *gpu,
113 const float color[4],
114 uint32_t dw[12])
115{
116 float rgba[4] = { color[0], color[1], color[2], color[3] };
117
118 INTEL_GPU_ASSERT(gpu, 6, 6);
119
120 /*
121 * This state is not documented in the Sandy Bridge PRM, but in the
122 * Ironlake PRM. SNORM8 seems to be in DW11 instead of DW1.
123 */
124
125 /* IEEE_FP */
126 dw[1] = u_fui(rgba[0]);
127 dw[2] = u_fui(rgba[1]);
128 dw[3] = u_fui(rgba[2]);
129 dw[4] = u_fui(rgba[3]);
130
131 /* FLOAT_16 */
132 dw[5] = u_float_to_half(rgba[0]) |
133 u_float_to_half(rgba[1]) << 16;
134 dw[6] = u_float_to_half(rgba[2]) |
135 u_float_to_half(rgba[3]) << 16;
136
137 /* clamp to [-1.0f, 1.0f] */
138 rgba[0] = U_CLAMP(rgba[0], -1.0f, 1.0f);
139 rgba[1] = U_CLAMP(rgba[1], -1.0f, 1.0f);
140 rgba[2] = U_CLAMP(rgba[2], -1.0f, 1.0f);
141 rgba[3] = U_CLAMP(rgba[3], -1.0f, 1.0f);
142
143 /* SNORM16 */
144 dw[9] = (int16_t) u_iround(rgba[0] * 32767.0f) |
145 (int16_t) u_iround(rgba[1] * 32767.0f) << 16;
146 dw[10] = (int16_t) u_iround(rgba[2] * 32767.0f) |
147 (int16_t) u_iround(rgba[3] * 32767.0f) << 16;
148
149 /* SNORM8 */
150 dw[11] = (int8_t) u_iround(rgba[0] * 127.0f) |
151 (int8_t) u_iround(rgba[1] * 127.0f) << 8 |
152 (int8_t) u_iround(rgba[2] * 127.0f) << 16 |
153 (int8_t) u_iround(rgba[3] * 127.0f) << 24;
154
155 /* clamp to [0.0f, 1.0f] */
156 rgba[0] = U_CLAMP(rgba[0], 0.0f, 1.0f);
157 rgba[1] = U_CLAMP(rgba[1], 0.0f, 1.0f);
158 rgba[2] = U_CLAMP(rgba[2], 0.0f, 1.0f);
159 rgba[3] = U_CLAMP(rgba[3], 0.0f, 1.0f);
160
161 /* UNORM8 */
162 dw[0] = (uint8_t) u_iround(rgba[0] * 255.0f) |
163 (uint8_t) u_iround(rgba[1] * 255.0f) << 8 |
164 (uint8_t) u_iround(rgba[2] * 255.0f) << 16 |
165 (uint8_t) u_iround(rgba[3] * 255.0f) << 24;
166
167 /* UNORM16 */
168 dw[7] = (uint16_t) u_iround(rgba[0] * 65535.0f) |
169 (uint16_t) u_iround(rgba[1] * 65535.0f) << 16;
170 dw[8] = (uint16_t) u_iround(rgba[2] * 65535.0f) |
171 (uint16_t) u_iround(rgba[3] * 65535.0f) << 16;
172}
173
174static void
Chia-I Wu375d0992014-08-18 23:38:23 +0800175sampler_init(struct intel_sampler *sampler,
176 const struct intel_gpu *gpu,
177 const XGL_SAMPLER_CREATE_INFO *info)
Chia-I Wu28b89962014-08-18 14:40:49 +0800178{
179 int mip_filter, min_filter, mag_filter, max_aniso;
180 int lod_bias, max_lod, min_lod;
181 int wrap_s, wrap_t, wrap_r;
182 uint32_t dw0, dw1, dw3;
183 float border_color[4];
184
185 INTEL_GPU_ASSERT(gpu, 6, 7.5);
Chia-I Wu375d0992014-08-18 23:38:23 +0800186 STATIC_ASSERT(ARRAY_SIZE(sampler->cmd) >= 15);
Chia-I Wu28b89962014-08-18 14:40:49 +0800187
188 mip_filter = translate_tex_mipmap_mode(info->mipMode);
189 min_filter = translate_tex_filter(info->minFilter);
190 mag_filter = translate_tex_filter(info->magFilter);
191
192 if (info->maxAnisotropy >= 2 && info->maxAnisotropy <= 16)
193 max_aniso = info->maxAnisotropy / 2 - 1;
194 else if (info->maxAnisotropy > 16)
195 max_aniso = GEN6_ANISORATIO_16;
196 else
197 max_aniso = GEN6_ANISORATIO_2;
198
199 /*
200 * Here is how the hardware calculate per-pixel LOD, from my reading of the
201 * PRMs:
202 *
203 * 1) LOD is set to log2(ratio of texels to pixels) if not specified in
204 * other ways. The number of texels is measured using level
205 * SurfMinLod.
206 * 2) Bias is added to LOD.
207 * 3) LOD is clamped to [MinLod, MaxLod], and the clamped value is
208 * compared with Base to determine whether magnification or
209 * minification is needed. (if preclamp is disabled, LOD is compared
210 * with Base before clamping)
211 * 4) If magnification is needed, or no mipmapping is requested, LOD is
212 * set to floor(MinLod).
213 * 5) LOD is clamped to [0, MIPCnt], and SurfMinLod is added to LOD.
214 *
215 * With Gallium interface, Base is always zero and
216 * pipe_sampler_view::u.tex.first_level specifies SurfMinLod.
217 */
218 if (intel_gpu_gen(gpu) >= INTEL_GEN(7)) {
219 const float scale = 256.0f;
220
221 /* [-16.0, 16.0) in S4.8 */
222 lod_bias = (int)
223 (U_CLAMP(info->mipLodBias, -16.0f, 15.9f) * scale);
224 lod_bias &= 0x1fff;
225
226 /* [0.0, 14.0] in U4.8 */
227 max_lod = (int) (U_CLAMP(info->maxLod, 0.0f, 14.0f) * scale);
228 min_lod = (int) (U_CLAMP(info->minLod, 0.0f, 14.0f) * scale);
229 }
230 else {
231 const float scale = 64.0f;
232
233 /* [-16.0, 16.0) in S4.6 */
234 lod_bias = (int)
235 (U_CLAMP(info->mipLodBias, -16.0f, 15.9f) * scale);
236 lod_bias &= 0x7ff;
237
238 /* [0.0, 13.0] in U4.6 */
239 max_lod = (int) (U_CLAMP(info->maxLod, 0.0f, 13.0f) * scale);
240 min_lod = (int) (U_CLAMP(info->minLod, 0.0f, 13.0f) * scale);
241 }
242
243 /*
244 * We want LOD to be clamped to determine magnification/minification, and
245 * get set to zero when it is magnification or when mipmapping is disabled.
246 * The hardware would set LOD to floor(MinLod) and that is a problem when
247 * MinLod is greater than or equal to 1.0f.
248 *
249 * With Base being zero, it is always minification when MinLod is non-zero.
250 * To achieve our goal, we just need to set MinLod to zero and set
251 * MagFilter to MinFilter when mipmapping is disabled.
252 */
253 if (info->mipMode == XGL_TEX_MIPMAP_BASE && min_lod) {
254 min_lod = 0;
255 mag_filter = min_filter;
256 }
257
258 /* determine wrap s/t/r */
259 wrap_s = translate_tex_addr(info->addressU);
260 wrap_t = translate_tex_addr(info->addressV);
261 wrap_r = translate_tex_addr(info->addressW);
262
263 translate_border_color(info->borderColorType, border_color);
264
265 if (intel_gpu_gen(gpu) >= INTEL_GEN(7)) {
266 dw0 = 1 << 28 |
267 mip_filter << 20 |
268 lod_bias << 1;
269
270 if (info->maxAnisotropy) {
271 dw0 |= GEN6_MAPFILTER_ANISOTROPIC << 17 |
272 GEN6_MAPFILTER_ANISOTROPIC << 14 |
273 1;
274 } else {
275 dw0 |= mag_filter << 17 |
276 min_filter << 14;
277 }
278
279 dw1 = min_lod << 20 |
280 max_lod << 8;
281
282 dw1 |= translate_compare_func(info->compareFunc) << 1;
283
284 dw3 = max_aniso << 19;
285
286 /* round the coordinates for linear filtering */
287 if (min_filter != GEN6_MAPFILTER_NEAREST) {
288 dw3 |= (GEN6_SAMPLER_DW3_U_MIN_ROUND |
289 GEN6_SAMPLER_DW3_V_MIN_ROUND |
290 GEN6_SAMPLER_DW3_R_MIN_ROUND);
291 }
292 if (mag_filter != GEN6_MAPFILTER_NEAREST) {
293 dw3 |= (GEN6_SAMPLER_DW3_U_MAG_ROUND |
294 GEN6_SAMPLER_DW3_V_MAG_ROUND |
295 GEN6_SAMPLER_DW3_R_MAG_ROUND);
296 }
297
298 dw3 |= wrap_s << 6 |
299 wrap_t << 3 |
300 wrap_r;
301
Chia-I Wu375d0992014-08-18 23:38:23 +0800302 sampler->cmd[0] = dw0;
303 sampler->cmd[1] = dw1;
304 sampler->cmd[2] = dw3;
Chia-I Wu28b89962014-08-18 14:40:49 +0800305
Chia-I Wu375d0992014-08-18 23:38:23 +0800306 memcpy(&sampler->cmd[3], &border_color, sizeof(border_color));
Chia-I Wu28b89962014-08-18 14:40:49 +0800307 }
308 else {
309 dw0 = 1 << 28 |
310 mip_filter << 20 |
311 lod_bias << 3;
312
313 dw0 |= translate_compare_func(info->compareFunc);
314
315 if (info->maxAnisotropy) {
316 dw0 |= GEN6_MAPFILTER_ANISOTROPIC << 17 |
317 GEN6_MAPFILTER_ANISOTROPIC << 14;
318 }
319 else {
320 dw0 |= (min_filter != mag_filter) << 27 |
321 mag_filter << 17 |
322 min_filter << 14;
323 }
324
325 dw1 = min_lod << 22 |
326 max_lod << 12;
327
328 dw1 |= wrap_s << 6 |
329 wrap_t << 3 |
330 wrap_r;
331
332 dw3 = max_aniso << 19;
333
334 /* round the coordinates for linear filtering */
335 if (min_filter != GEN6_MAPFILTER_NEAREST) {
336 dw3 |= (GEN6_SAMPLER_DW3_U_MIN_ROUND |
337 GEN6_SAMPLER_DW3_V_MIN_ROUND |
338 GEN6_SAMPLER_DW3_R_MIN_ROUND);
339 }
340 if (mag_filter != GEN6_MAPFILTER_NEAREST) {
341 dw3 |= (GEN6_SAMPLER_DW3_U_MAG_ROUND |
342 GEN6_SAMPLER_DW3_V_MAG_ROUND |
343 GEN6_SAMPLER_DW3_R_MAG_ROUND);
344 }
345
Chia-I Wu375d0992014-08-18 23:38:23 +0800346 sampler->cmd[0] = dw0;
347 sampler->cmd[1] = dw1;
348 sampler->cmd[2] = dw3;
Chia-I Wu28b89962014-08-18 14:40:49 +0800349
Chia-I Wu375d0992014-08-18 23:38:23 +0800350 emit_border_color_gen6(gpu, border_color, &sampler->cmd[3]);
Chia-I Wu28b89962014-08-18 14:40:49 +0800351 }
352}
353
354static void sampler_destroy(struct intel_obj *obj)
355{
356 struct intel_sampler *sampler = intel_sampler_from_obj(obj);
357
358 intel_sampler_destroy(sampler);
359}
360
361XGL_RESULT intel_sampler_create(struct intel_dev *dev,
362 const XGL_SAMPLER_CREATE_INFO *info,
363 struct intel_sampler **sampler_ret)
364{
365 struct intel_sampler *sampler;
366
367 sampler = (struct intel_sampler *) intel_base_create(dev,
368 sizeof(*sampler), dev->base.dbg, XGL_DBG_OBJECT_SAMPLER, info, 0);
369 if (!sampler)
370 return XGL_ERROR_OUT_OF_MEMORY;
371
372 sampler->obj.destroy = sampler_destroy;
373
Chia-I Wu375d0992014-08-18 23:38:23 +0800374 sampler_init(sampler, dev->gpu, info);
Chia-I Wu28b89962014-08-18 14:40:49 +0800375
376 *sampler_ret = sampler;
377
378 return XGL_SUCCESS;
379}
380
381void intel_sampler_destroy(struct intel_sampler *sampler)
382{
383 intel_base_destroy(&sampler->obj.base);
384}
385
386XGL_RESULT XGLAPI intelCreateSampler(
387 XGL_DEVICE device,
388 const XGL_SAMPLER_CREATE_INFO* pCreateInfo,
389 XGL_SAMPLER* pSampler)
390{
391 struct intel_dev *dev = intel_dev(device);
392
393 return intel_sampler_create(dev, pCreateInfo,
394 (struct intel_sampler **) pSampler);
395}