blob: b7910a923e46b88573531e3572409ce73bed4e5d [file] [log] [blame]
Chia-I Wu28b89962014-08-18 14:40:49 +08001/*
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu28b89962014-08-18 14:40:49 +08003 *
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 */
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -060035static int translate_tex_filter(VkTexFilter filter)
Chia-I Wu28b89962014-08-18 14:40:49 +080036{
37 switch (filter) {
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -060038 case VK_TEX_FILTER_NEAREST: return GEN6_MAPFILTER_NEAREST;
39 case VK_TEX_FILTER_LINEAR: return GEN6_MAPFILTER_LINEAR;
Chia-I Wu28b89962014-08-18 14:40:49 +080040 default:
41 assert(!"unknown tex filter");
42 return GEN6_MAPFILTER_NEAREST;
43 }
44}
45
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -060046static int translate_tex_mipmap_mode(VkTexMipmapMode mode)
Chia-I Wu28b89962014-08-18 14:40:49 +080047{
48 switch (mode) {
Tony Barbour8205d902015-04-16 15:59:00 -060049 case VK_TEX_MIPMAP_MODE_NEAREST: return GEN6_MIPFILTER_NEAREST;
50 case VK_TEX_MIPMAP_MODE_LINEAR: return GEN6_MIPFILTER_LINEAR;
51 case VK_TEX_MIPMAP_MODE_BASE: return GEN6_MIPFILTER_NONE;
Chia-I Wu28b89962014-08-18 14:40:49 +080052 default:
53 assert(!"unknown tex mipmap mode");
54 return GEN6_MIPFILTER_NONE;
55 }
56}
57
Courtney Goeltzenleuchter51624412015-09-10 14:08:50 -060058static int translate_tex_addr(VkTexAddressMode addr)
Chia-I Wu28b89962014-08-18 14:40:49 +080059{
60 switch (addr) {
Courtney Goeltzenleuchter51624412015-09-10 14:08:50 -060061 case VK_TEX_ADDRESS_MODE_WRAP: return GEN6_TEXCOORDMODE_WRAP;
62 case VK_TEX_ADDRESS_MODE_MIRROR: return GEN6_TEXCOORDMODE_MIRROR;
63 case VK_TEX_ADDRESS_MODE_CLAMP: return GEN6_TEXCOORDMODE_CLAMP;
64 case VK_TEX_ADDRESS_MODE_MIRROR_ONCE: return GEN6_TEXCOORDMODE_MIRROR_ONCE;
65 case VK_TEX_ADDRESS_MODE_CLAMP_BORDER: return GEN6_TEXCOORDMODE_CLAMP_BORDER;
Chia-I Wu28b89962014-08-18 14:40:49 +080066 default:
67 assert(!"unknown tex address");
68 return GEN6_TEXCOORDMODE_WRAP;
69 }
70}
71
Tony Barbour8205d902015-04-16 15:59:00 -060072static int translate_compare_func(VkCompareOp func)
Chia-I Wu28b89962014-08-18 14:40:49 +080073{
74 switch (func) {
Tony Barbour8205d902015-04-16 15:59:00 -060075 case VK_COMPARE_OP_NEVER: return GEN6_COMPAREFUNCTION_NEVER;
76 case VK_COMPARE_OP_LESS: return GEN6_COMPAREFUNCTION_LESS;
77 case VK_COMPARE_OP_EQUAL: return GEN6_COMPAREFUNCTION_EQUAL;
78 case VK_COMPARE_OP_LESS_EQUAL: return GEN6_COMPAREFUNCTION_LEQUAL;
79 case VK_COMPARE_OP_GREATER: return GEN6_COMPAREFUNCTION_GREATER;
80 case VK_COMPARE_OP_NOT_EQUAL: return GEN6_COMPAREFUNCTION_NOTEQUAL;
81 case VK_COMPARE_OP_GREATER_EQUAL: return GEN6_COMPAREFUNCTION_GEQUAL;
82 case VK_COMPARE_OP_ALWAYS: return GEN6_COMPAREFUNCTION_ALWAYS;
Chia-I Wu28b89962014-08-18 14:40:49 +080083 default:
84 assert(!"unknown compare_func");
85 return GEN6_COMPAREFUNCTION_NEVER;
86 }
87}
88
Tony Barbour8205d902015-04-16 15:59:00 -060089static void translate_border_color(VkBorderColor type, float rgba[4])
Chia-I Wu28b89962014-08-18 14:40:49 +080090{
91 switch (type) {
Tony Barbour2c4e7c72015-06-25 16:56:44 -060092 case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
93 case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
Chia-I Wu28b89962014-08-18 14:40:49 +080094 rgba[0] = 1.0;
95 rgba[1] = 1.0;
96 rgba[2] = 1.0;
97 rgba[3] = 1.0;
98 break;
Tony Barbour2c4e7c72015-06-25 16:56:44 -060099 case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
100 case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
Chia-I Wu28b89962014-08-18 14:40:49 +0800101 default:
102 rgba[0] = 0.0;
103 rgba[1] = 0.0;
104 rgba[2] = 0.0;
105 rgba[3] = 0.0;
106 break;
Tony Barbour2c4e7c72015-06-25 16:56:44 -0600107 case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
108 case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
Chia-I Wu28b89962014-08-18 14:40:49 +0800109 rgba[0] = 0.0;
110 rgba[1] = 0.0;
111 rgba[2] = 0.0;
112 rgba[3] = 1.0;
113 break;
114 }
115}
116
117static void
Chia-I Wu06bed192014-08-20 13:57:18 +0800118sampler_border_color_state_gen6(const struct intel_gpu *gpu,
119 const float color[4],
120 uint32_t dw[12])
Chia-I Wu28b89962014-08-18 14:40:49 +0800121{
122 float rgba[4] = { color[0], color[1], color[2], color[3] };
123
124 INTEL_GPU_ASSERT(gpu, 6, 6);
125
126 /*
127 * This state is not documented in the Sandy Bridge PRM, but in the
128 * Ironlake PRM. SNORM8 seems to be in DW11 instead of DW1.
129 */
130
131 /* IEEE_FP */
132 dw[1] = u_fui(rgba[0]);
133 dw[2] = u_fui(rgba[1]);
134 dw[3] = u_fui(rgba[2]);
135 dw[4] = u_fui(rgba[3]);
136
137 /* FLOAT_16 */
138 dw[5] = u_float_to_half(rgba[0]) |
139 u_float_to_half(rgba[1]) << 16;
140 dw[6] = u_float_to_half(rgba[2]) |
141 u_float_to_half(rgba[3]) << 16;
142
143 /* clamp to [-1.0f, 1.0f] */
144 rgba[0] = U_CLAMP(rgba[0], -1.0f, 1.0f);
145 rgba[1] = U_CLAMP(rgba[1], -1.0f, 1.0f);
146 rgba[2] = U_CLAMP(rgba[2], -1.0f, 1.0f);
147 rgba[3] = U_CLAMP(rgba[3], -1.0f, 1.0f);
148
149 /* SNORM16 */
150 dw[9] = (int16_t) u_iround(rgba[0] * 32767.0f) |
151 (int16_t) u_iround(rgba[1] * 32767.0f) << 16;
152 dw[10] = (int16_t) u_iround(rgba[2] * 32767.0f) |
153 (int16_t) u_iround(rgba[3] * 32767.0f) << 16;
154
155 /* SNORM8 */
156 dw[11] = (int8_t) u_iround(rgba[0] * 127.0f) |
157 (int8_t) u_iround(rgba[1] * 127.0f) << 8 |
158 (int8_t) u_iround(rgba[2] * 127.0f) << 16 |
159 (int8_t) u_iround(rgba[3] * 127.0f) << 24;
160
161 /* clamp to [0.0f, 1.0f] */
162 rgba[0] = U_CLAMP(rgba[0], 0.0f, 1.0f);
163 rgba[1] = U_CLAMP(rgba[1], 0.0f, 1.0f);
164 rgba[2] = U_CLAMP(rgba[2], 0.0f, 1.0f);
165 rgba[3] = U_CLAMP(rgba[3], 0.0f, 1.0f);
166
167 /* UNORM8 */
168 dw[0] = (uint8_t) u_iround(rgba[0] * 255.0f) |
169 (uint8_t) u_iround(rgba[1] * 255.0f) << 8 |
170 (uint8_t) u_iround(rgba[2] * 255.0f) << 16 |
171 (uint8_t) u_iround(rgba[3] * 255.0f) << 24;
172
173 /* UNORM16 */
174 dw[7] = (uint16_t) u_iround(rgba[0] * 65535.0f) |
175 (uint16_t) u_iround(rgba[1] * 65535.0f) << 16;
176 dw[8] = (uint16_t) u_iround(rgba[2] * 65535.0f) |
177 (uint16_t) u_iround(rgba[3] * 65535.0f) << 16;
178}
179
180static void
Chia-I Wu375d0992014-08-18 23:38:23 +0800181sampler_init(struct intel_sampler *sampler,
182 const struct intel_gpu *gpu,
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600183 const VkSamplerCreateInfo *info)
Chia-I Wu28b89962014-08-18 14:40:49 +0800184{
185 int mip_filter, min_filter, mag_filter, max_aniso;
186 int lod_bias, max_lod, min_lod;
187 int wrap_s, wrap_t, wrap_r;
188 uint32_t dw0, dw1, dw3;
189 float border_color[4];
190
191 INTEL_GPU_ASSERT(gpu, 6, 7.5);
Chia-I Wu375d0992014-08-18 23:38:23 +0800192 STATIC_ASSERT(ARRAY_SIZE(sampler->cmd) >= 15);
Chia-I Wu28b89962014-08-18 14:40:49 +0800193
194 mip_filter = translate_tex_mipmap_mode(info->mipMode);
195 min_filter = translate_tex_filter(info->minFilter);
196 mag_filter = translate_tex_filter(info->magFilter);
197
198 if (info->maxAnisotropy >= 2 && info->maxAnisotropy <= 16)
199 max_aniso = info->maxAnisotropy / 2 - 1;
200 else if (info->maxAnisotropy > 16)
201 max_aniso = GEN6_ANISORATIO_16;
202 else
203 max_aniso = GEN6_ANISORATIO_2;
204
205 /*
206 * Here is how the hardware calculate per-pixel LOD, from my reading of the
207 * PRMs:
208 *
209 * 1) LOD is set to log2(ratio of texels to pixels) if not specified in
210 * other ways. The number of texels is measured using level
211 * SurfMinLod.
212 * 2) Bias is added to LOD.
213 * 3) LOD is clamped to [MinLod, MaxLod], and the clamped value is
214 * compared with Base to determine whether magnification or
215 * minification is needed. (if preclamp is disabled, LOD is compared
216 * with Base before clamping)
217 * 4) If magnification is needed, or no mipmapping is requested, LOD is
218 * set to floor(MinLod).
219 * 5) LOD is clamped to [0, MIPCnt], and SurfMinLod is added to LOD.
220 *
221 * With Gallium interface, Base is always zero and
222 * pipe_sampler_view::u.tex.first_level specifies SurfMinLod.
223 */
224 if (intel_gpu_gen(gpu) >= INTEL_GEN(7)) {
225 const float scale = 256.0f;
226
227 /* [-16.0, 16.0) in S4.8 */
228 lod_bias = (int)
229 (U_CLAMP(info->mipLodBias, -16.0f, 15.9f) * scale);
230 lod_bias &= 0x1fff;
231
232 /* [0.0, 14.0] in U4.8 */
233 max_lod = (int) (U_CLAMP(info->maxLod, 0.0f, 14.0f) * scale);
234 min_lod = (int) (U_CLAMP(info->minLod, 0.0f, 14.0f) * scale);
235 }
236 else {
237 const float scale = 64.0f;
238
239 /* [-16.0, 16.0) in S4.6 */
240 lod_bias = (int)
241 (U_CLAMP(info->mipLodBias, -16.0f, 15.9f) * scale);
242 lod_bias &= 0x7ff;
243
244 /* [0.0, 13.0] in U4.6 */
245 max_lod = (int) (U_CLAMP(info->maxLod, 0.0f, 13.0f) * scale);
246 min_lod = (int) (U_CLAMP(info->minLod, 0.0f, 13.0f) * scale);
247 }
248
249 /*
250 * We want LOD to be clamped to determine magnification/minification, and
251 * get set to zero when it is magnification or when mipmapping is disabled.
252 * The hardware would set LOD to floor(MinLod) and that is a problem when
253 * MinLod is greater than or equal to 1.0f.
254 *
255 * With Base being zero, it is always minification when MinLod is non-zero.
256 * To achieve our goal, we just need to set MinLod to zero and set
257 * MagFilter to MinFilter when mipmapping is disabled.
258 */
Tony Barbour8205d902015-04-16 15:59:00 -0600259 if (info->mipMode == VK_TEX_MIPMAP_MODE_BASE && min_lod) {
Chia-I Wu28b89962014-08-18 14:40:49 +0800260 min_lod = 0;
261 mag_filter = min_filter;
262 }
263
264 /* determine wrap s/t/r */
Courtney Goeltzenleuchter51624412015-09-10 14:08:50 -0600265 wrap_s = translate_tex_addr(info->addressModeU);
266 wrap_t = translate_tex_addr(info->addressModeV);
267 wrap_r = translate_tex_addr(info->addressModeW);
Chia-I Wu28b89962014-08-18 14:40:49 +0800268
Tony Barbour8205d902015-04-16 15:59:00 -0600269 translate_border_color(info->borderColor, border_color);
Chia-I Wu28b89962014-08-18 14:40:49 +0800270
271 if (intel_gpu_gen(gpu) >= INTEL_GEN(7)) {
272 dw0 = 1 << 28 |
273 mip_filter << 20 |
274 lod_bias << 1;
275
Cody Northropa67947b2015-01-02 14:06:12 -0700276 if (info->maxAnisotropy > 1) {
Chia-I Wu28b89962014-08-18 14:40:49 +0800277 dw0 |= GEN6_MAPFILTER_ANISOTROPIC << 17 |
278 GEN6_MAPFILTER_ANISOTROPIC << 14 |
279 1;
280 } else {
281 dw0 |= mag_filter << 17 |
282 min_filter << 14;
283 }
284
285 dw1 = min_lod << 20 |
286 max_lod << 8;
287
Tony Barbour8205d902015-04-16 15:59:00 -0600288 dw1 |= translate_compare_func(info->compareOp) << 1;
Chia-I Wu28b89962014-08-18 14:40:49 +0800289
290 dw3 = max_aniso << 19;
291
292 /* round the coordinates for linear filtering */
293 if (min_filter != GEN6_MAPFILTER_NEAREST) {
294 dw3 |= (GEN6_SAMPLER_DW3_U_MIN_ROUND |
295 GEN6_SAMPLER_DW3_V_MIN_ROUND |
296 GEN6_SAMPLER_DW3_R_MIN_ROUND);
297 }
298 if (mag_filter != GEN6_MAPFILTER_NEAREST) {
299 dw3 |= (GEN6_SAMPLER_DW3_U_MAG_ROUND |
300 GEN6_SAMPLER_DW3_V_MAG_ROUND |
301 GEN6_SAMPLER_DW3_R_MAG_ROUND);
302 }
303
304 dw3 |= wrap_s << 6 |
305 wrap_t << 3 |
306 wrap_r;
307
Mark Lobodzinski513acdf2015-09-01 15:42:56 -0600308 if (info->unnormalizedCoordinates)
Cody Northrop0bf4e1d2015-08-11 15:50:55 -0600309 dw3 |= GEN7_SAMPLER_DW3_NON_NORMALIZED_COORD;
310
Chia-I Wu375d0992014-08-18 23:38:23 +0800311 sampler->cmd[0] = dw0;
312 sampler->cmd[1] = dw1;
313 sampler->cmd[2] = dw3;
Chia-I Wu28b89962014-08-18 14:40:49 +0800314
Chia-I Wu375d0992014-08-18 23:38:23 +0800315 memcpy(&sampler->cmd[3], &border_color, sizeof(border_color));
Chia-I Wu28b89962014-08-18 14:40:49 +0800316 }
317 else {
318 dw0 = 1 << 28 |
319 mip_filter << 20 |
320 lod_bias << 3;
321
Tony Barbour8205d902015-04-16 15:59:00 -0600322 dw0 |= translate_compare_func(info->compareOp);
Chia-I Wu28b89962014-08-18 14:40:49 +0800323
Cody Northropa67947b2015-01-02 14:06:12 -0700324 if (info->maxAnisotropy > 1) {
Chia-I Wu28b89962014-08-18 14:40:49 +0800325 dw0 |= GEN6_MAPFILTER_ANISOTROPIC << 17 |
326 GEN6_MAPFILTER_ANISOTROPIC << 14;
327 }
328 else {
329 dw0 |= (min_filter != mag_filter) << 27 |
330 mag_filter << 17 |
331 min_filter << 14;
332 }
333
334 dw1 = min_lod << 22 |
335 max_lod << 12;
336
337 dw1 |= wrap_s << 6 |
338 wrap_t << 3 |
339 wrap_r;
340
341 dw3 = max_aniso << 19;
342
343 /* round the coordinates for linear filtering */
344 if (min_filter != GEN6_MAPFILTER_NEAREST) {
345 dw3 |= (GEN6_SAMPLER_DW3_U_MIN_ROUND |
346 GEN6_SAMPLER_DW3_V_MIN_ROUND |
347 GEN6_SAMPLER_DW3_R_MIN_ROUND);
348 }
349 if (mag_filter != GEN6_MAPFILTER_NEAREST) {
350 dw3 |= (GEN6_SAMPLER_DW3_U_MAG_ROUND |
351 GEN6_SAMPLER_DW3_V_MAG_ROUND |
352 GEN6_SAMPLER_DW3_R_MAG_ROUND);
353 }
354
Mark Lobodzinski513acdf2015-09-01 15:42:56 -0600355 if (info->unnormalizedCoordinates)
Cody Northrop0bf4e1d2015-08-11 15:50:55 -0600356 dw3 |= GEN6_SAMPLER_DW3_NON_NORMALIZED_COORD;
357
Chia-I Wu375d0992014-08-18 23:38:23 +0800358 sampler->cmd[0] = dw0;
359 sampler->cmd[1] = dw1;
360 sampler->cmd[2] = dw3;
Chia-I Wu28b89962014-08-18 14:40:49 +0800361
Chia-I Wu06bed192014-08-20 13:57:18 +0800362 sampler_border_color_state_gen6(gpu, border_color, &sampler->cmd[3]);
Chia-I Wu28b89962014-08-18 14:40:49 +0800363 }
364}
365
366static void sampler_destroy(struct intel_obj *obj)
367{
368 struct intel_sampler *sampler = intel_sampler_from_obj(obj);
369
370 intel_sampler_destroy(sampler);
371}
372
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600373VkResult intel_sampler_create(struct intel_dev *dev,
374 const VkSamplerCreateInfo *info,
Chia-I Wu28b89962014-08-18 14:40:49 +0800375 struct intel_sampler **sampler_ret)
376{
377 struct intel_sampler *sampler;
378
Chia-I Wu545c2e12015-02-22 13:19:54 +0800379 sampler = (struct intel_sampler *) intel_base_create(&dev->base.handle,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600380 sizeof(*sampler), dev->base.dbg, VK_OBJECT_TYPE_SAMPLER, info, 0);
Chia-I Wu28b89962014-08-18 14:40:49 +0800381 if (!sampler)
Tony Barbour8205d902015-04-16 15:59:00 -0600382 return VK_ERROR_OUT_OF_HOST_MEMORY;
Chia-I Wu28b89962014-08-18 14:40:49 +0800383
384 sampler->obj.destroy = sampler_destroy;
385
Chia-I Wu375d0992014-08-18 23:38:23 +0800386 sampler_init(sampler, dev->gpu, info);
Chia-I Wu28b89962014-08-18 14:40:49 +0800387
388 *sampler_ret = sampler;
389
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600390 return VK_SUCCESS;
Chia-I Wu28b89962014-08-18 14:40:49 +0800391}
392
393void intel_sampler_destroy(struct intel_sampler *sampler)
394{
395 intel_base_destroy(&sampler->obj.base);
396}
397
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600398ICD_EXPORT VkResult VKAPI vkCreateSampler(
399 VkDevice device,
400 const VkSamplerCreateInfo* pCreateInfo,
401 VkSampler* pSampler)
Chia-I Wu28b89962014-08-18 14:40:49 +0800402{
403 struct intel_dev *dev = intel_dev(device);
404
405 return intel_sampler_create(dev, pCreateInfo,
406 (struct intel_sampler **) pSampler);
407}
Tony Barbourde4124d2015-07-03 10:33:54 -0600408
Mark Lobodzinski67b42b72015-09-07 13:59:43 -0600409ICD_EXPORT void VKAPI vkDestroySampler(
Tony Barbourde4124d2015-07-03 10:33:54 -0600410 VkDevice device,
411 VkSampler sampler)
412
413 {
414 struct intel_obj *obj = intel_obj(sampler.handle);
415
416 obj->destroy(obj);
Tony Barbourde4124d2015-07-03 10:33:54 -0600417 }