1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Valve Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#ifndef __FREEDRENO_GUARDBAND_H__ 25bf215546Sopenharmony_ci#define __FREEDRENO_GUARDBAND_H__ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include <assert.h> 28bf215546Sopenharmony_ci#include <math.h> 29bf215546Sopenharmony_ci#include <stdbool.h> 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_cistatic inline unsigned 32bf215546Sopenharmony_cifd_calc_guardband(float offset, float scale, bool is_a3xx) 33bf215546Sopenharmony_ci{ 34bf215546Sopenharmony_ci /* On a3xx, the viewport max is 4k and the docs say the max guardband 35bf215546Sopenharmony_ci * width is 8k. That is, GRAS cannot handle triangle coordinates more than 36bf215546Sopenharmony_ci * 8k, positive or negative. On a4xx+ the viewport width was bumped to 37bf215546Sopenharmony_ci * 16k, and so the guardband width was necessarily also bumped. Note that 38bf215546Sopenharmony_ci * the numbers here should correspond to 39bf215546Sopenharmony_ci * VkPhysicalDeviceLimits::viewportBoundsRange in Vulkan. 40bf215546Sopenharmony_ci */ 41bf215546Sopenharmony_ci const float gb_min = is_a3xx ? -8192. : -32768.; 42bf215546Sopenharmony_ci const float gb_max = is_a3xx ? 8191. : 32767.; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci /* Clipping happens in normalized device coordinates, so we have to 45bf215546Sopenharmony_ci * transform gb_min and gb_max to ndc using the inverse of the viewport 46bf215546Sopenharmony_ci * transform. Avoid flipping min and max by using the absolute value of 47bf215546Sopenharmony_ci * the scale. 48bf215546Sopenharmony_ci */ 49bf215546Sopenharmony_ci const float gb_min_ndc = (gb_min - offset) / fabsf(scale); 50bf215546Sopenharmony_ci const float gb_max_ndc = (gb_max - offset) / fabsf(scale); 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci /* There's only one GB_ADJ field, so presumably the guardband is 53bf215546Sopenharmony_ci * [-GB_ADJ, GB_ADJ] like on Radeon. It's always safe to make the 54bf215546Sopenharmony_ci * guardband smaller, so we have to take the min to get the largest range 55bf215546Sopenharmony_ci * contained in [gb_min_ndc, gb_max_ndc]. 56bf215546Sopenharmony_ci */ 57bf215546Sopenharmony_ci const float gb_adj = fminf(-gb_min_ndc, gb_max_ndc); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci /* The viewport should always be contained in the guardband. */ 60bf215546Sopenharmony_ci assert(gb_adj >= 1.0); 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci /* frexp returns an unspecified value if given an infinite value, which 63bf215546Sopenharmony_ci * can happen if scale == 0. 64bf215546Sopenharmony_ci */ 65bf215546Sopenharmony_ci if (isinf(gb_adj)) 66bf215546Sopenharmony_ci return 0x1ff; 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci /* Convert gb_adj to 3.6 floating point, rounding down since it's always 69bf215546Sopenharmony_ci * safe to make the guard band smaller (but not the other way around!). 70bf215546Sopenharmony_ci * 71bf215546Sopenharmony_ci * Note: After converting back to a float, the value the blob returns here 72bf215546Sopenharmony_ci * is sometimes a little smaller than the value we return. This seems to 73bf215546Sopenharmony_ci * happen around the boundary between two different rounded values. For 74bf215546Sopenharmony_ci * example, using the a6xx blob: 75bf215546Sopenharmony_ci * 76bf215546Sopenharmony_ci * min | width | unrounded gb_adj | blob result | mesa result 77bf215546Sopenharmony_ci * ------------------------------------------------------------ 78bf215546Sopenharmony_ci * 0 | 510 | 127.498 | 127. | 127. 79bf215546Sopenharmony_ci * 0 | 511 | 127.247 | 126. | 127. 80bf215546Sopenharmony_ci * 0 | 512 | 126.996 | 126. | 126. 81bf215546Sopenharmony_ci * 82bf215546Sopenharmony_ci * The guardband must be 32767 wide, since that's what the blob reports 83bf215546Sopenharmony_ci * for viewportBoundsRange, so I'm guessing that they're rounding slightly 84bf215546Sopenharmony_ci * more conservatively somehow. 85bf215546Sopenharmony_ci */ 86bf215546Sopenharmony_ci int gb_adj_exp; 87bf215546Sopenharmony_ci float gb_adj_mantissa = frexpf(gb_adj, &gb_adj_exp); 88bf215546Sopenharmony_ci assert(gb_adj_exp > 0); 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci /* Round non-representable numbers down to the largest possible number. */ 91bf215546Sopenharmony_ci if (gb_adj_exp > 8) 92bf215546Sopenharmony_ci return 0x1ff; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci return ((gb_adj_exp - 1) << 6) | 95bf215546Sopenharmony_ci ((unsigned)truncf(gb_adj_mantissa * (1 << 7)) - (1 << 6)); 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci#endif /* __FREEDRENO_GUARDBAND_H__ */ 99