diff --git a/src/imagination/vulkan/meson.build b/src/imagination/vulkan/meson.build index 0444dfc57a4..bec467b97c6 100644 --- a/src/imagination/vulkan/meson.build +++ b/src/imagination/vulkan/meson.build @@ -51,6 +51,7 @@ pvr_files = files( 'pvr_query_compute.c', 'pvr_queue.c', 'pvr_robustness.c', + 'pvr_sampler.c', 'pvr_spm.c', 'pvr_tex_state.c', 'pvr_usc.c', diff --git a/src/imagination/vulkan/pvr_border.c b/src/imagination/vulkan/pvr_border.c index 39d2b5d0ad8..e2db574daca 100644 --- a/src/imagination/vulkan/pvr_border.c +++ b/src/imagination/vulkan/pvr_border.c @@ -35,6 +35,7 @@ #include "pvr_formats.h" #include "pvr_macros.h" #include "pvr_physical_device.h" +#include "pvr_sampler.h" #include "util/bitset.h" #include "util/format/u_format.h" #include "util/format/u_formats.h" diff --git a/src/imagination/vulkan/pvr_common.h b/src/imagination/vulkan/pvr_common.h index b400a61c2cc..643c95e9bd1 100644 --- a/src/imagination/vulkan/pvr_common.h +++ b/src/imagination/vulkan/pvr_common.h @@ -48,7 +48,6 @@ #include "util/vma.h" #include "vk_descriptor_set_layout.h" #include "vk_object.h" -#include "vk_sampler.h" #include "vk_sync.h" #define PVR_WORKGROUP_DIMENSIONS 3U @@ -226,12 +225,6 @@ static_assert( (PCO_IMAGE_META_COUNT + PCO_SAMPLER_META_COUNT) * sizeof(uint32_t), "pvr_combined_image_sampler_descriptor size is invalid."); -struct pvr_sampler { - struct vk_sampler vk; - struct pvr_sampler_descriptor descriptor; - uint32_t border_color_table_index; -}; - struct pvr_event { struct vk_object_base base; @@ -263,9 +256,5 @@ struct pvr_pds_upload { }; VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_event, base, VkEvent, VK_OBJECT_TYPE_EVENT) -VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_sampler, - vk.base, - VkSampler, - VK_OBJECT_TYPE_SAMPLER) #endif /* PVR_COMMON_H */ diff --git a/src/imagination/vulkan/pvr_descriptor_set.c b/src/imagination/vulkan/pvr_descriptor_set.c index e00ad873879..9eb0de2e6e8 100644 --- a/src/imagination/vulkan/pvr_descriptor_set.c +++ b/src/imagination/vulkan/pvr_descriptor_set.c @@ -38,6 +38,7 @@ #include "pvr_entrypoints.h" #include "pvr_image.h" #include "pvr_physical_device.h" +#include "pvr_sampler.h" #include "pvr_types.h" #include "util/compiler.h" #include "util/list.h" diff --git a/src/imagination/vulkan/pvr_device.c b/src/imagination/vulkan/pvr_device.c index d5511602fba..4e663be3375 100644 --- a/src/imagination/vulkan/pvr_device.c +++ b/src/imagination/vulkan/pvr_device.c @@ -2038,220 +2038,6 @@ void pvr_DestroyFramebuffer(VkDevice _device, vk_free2(&device->vk.alloc, pAllocator, framebuffer); } -static uint32_t -pvr_sampler_get_hw_filter_from_vk(const struct pvr_device_info *dev_info, - VkFilter filter) -{ - switch (filter) { - case VK_FILTER_NEAREST: - return ROGUE_TEXSTATE_FILTER_POINT; - case VK_FILTER_LINEAR: - return ROGUE_TEXSTATE_FILTER_LINEAR; - default: - UNREACHABLE("Unknown filter type."); - } -} - -static uint32_t -pvr_sampler_get_hw_addr_mode_from_vk(VkSamplerAddressMode addr_mode) -{ - switch (addr_mode) { - case VK_SAMPLER_ADDRESS_MODE_REPEAT: - return ROGUE_TEXSTATE_ADDRMODE_REPEAT; - case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: - return ROGUE_TEXSTATE_ADDRMODE_FLIP; - case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: - return ROGUE_TEXSTATE_ADDRMODE_CLAMP_TO_EDGE; - case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: - return ROGUE_TEXSTATE_ADDRMODE_FLIP_ONCE_THEN_CLAMP; - case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: - return ROGUE_TEXSTATE_ADDRMODE_CLAMP_TO_BORDER; - default: - UNREACHABLE("Invalid sampler address mode."); - } -} - -VkResult pvr_CreateSampler(VkDevice _device, - const VkSamplerCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSampler *pSampler) -{ - VK_FROM_HANDLE(pvr_device, device, _device); - struct pvr_sampler *sampler; - float lod_rounding_bias; - VkFilter min_filter; - VkFilter mag_filter; - VkResult result; - float min_lod; - float max_lod; - - sampler = - vk_sampler_create(&device->vk, pCreateInfo, pAllocator, sizeof(*sampler)); - if (!sampler) { - result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); - goto err_out; - } - - mag_filter = pCreateInfo->magFilter; - min_filter = pCreateInfo->minFilter; - - result = pvr_border_color_table_get_or_create_entry( - device, - sampler, - &device->border_color_table, - &sampler->border_color_table_index); - if (result != VK_SUCCESS) - goto err_free_sampler; - - if (PVR_HAS_QUIRK(&device->pdevice->dev_info, 51025)) { - /* The min/mag filters may need adjustment here, the GPU should decide - * which of the two filters to use based on the clamped LOD value: LOD - * <= 0 implies magnification, while LOD > 0 implies minification. - * - * As a workaround, we override magFilter with minFilter if we know that - * the magnification filter will never be used due to clamping anyway - * (i.e. minLod > 0). Conversely, we override minFilter with magFilter - * if maxLod <= 0. - */ - if (pCreateInfo->minLod > 0.0f) { - /* The clamped LOD will always be positive => always minify. */ - mag_filter = pCreateInfo->minFilter; - } - - if (pCreateInfo->maxLod <= 0.0f) { - /* The clamped LOD will always be negative or zero => always - * magnify. - */ - min_filter = pCreateInfo->magFilter; - } - } - - if (pCreateInfo->compareEnable) { - sampler->descriptor.meta[PCO_SAMPLER_META_COMPARE_OP] = - pCreateInfo->compareOp; - } else { - sampler->descriptor.meta[PCO_SAMPLER_META_COMPARE_OP] = - VK_COMPARE_OP_NEVER; - } - - pvr_csb_pack (&sampler->descriptor.words[0], TEXSTATE_SAMPLER_WORD0, word) { - const struct pvr_device_info *dev_info = &device->pdevice->dev_info; - const float lod_clamp_max = (float)ROGUE_TEXSTATE_CLAMP_MAX / - (1 << ROGUE_TEXSTATE_CLAMP_FRACTIONAL_BITS); - const float max_dadjust = ((float)(ROGUE_TEXSTATE_DADJUST_MAX_UINT - - ROGUE_TEXSTATE_DADJUST_ZERO_UINT)) / - (1 << ROGUE_TEXSTATE_DADJUST_FRACTIONAL_BITS); - const float min_dadjust = ((float)(ROGUE_TEXSTATE_DADJUST_MIN_UINT - - ROGUE_TEXSTATE_DADJUST_ZERO_UINT)) / - (1 << ROGUE_TEXSTATE_DADJUST_FRACTIONAL_BITS); - - word.magfilter = pvr_sampler_get_hw_filter_from_vk(dev_info, mag_filter); - word.minfilter = pvr_sampler_get_hw_filter_from_vk(dev_info, min_filter); - - if (pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR) - word.mipfilter = true; - - word.addrmode_u = - pvr_sampler_get_hw_addr_mode_from_vk(pCreateInfo->addressModeU); - word.addrmode_v = - pvr_sampler_get_hw_addr_mode_from_vk(pCreateInfo->addressModeV); - word.addrmode_w = - pvr_sampler_get_hw_addr_mode_from_vk(pCreateInfo->addressModeW); - - /* The Vulkan 1.0.205 spec says: - * - * The absolute value of mipLodBias must be less than or equal to - * VkPhysicalDeviceLimits::maxSamplerLodBias. - */ - word.dadjust = - ROGUE_TEXSTATE_DADJUST_ZERO_UINT + - util_signed_fixed( - CLAMP(pCreateInfo->mipLodBias, min_dadjust, max_dadjust), - ROGUE_TEXSTATE_DADJUST_FRACTIONAL_BITS); - - word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_DISABLED; - if (pCreateInfo->anisotropyEnable) { - if (pCreateInfo->maxAnisotropy >= 16.0f) - word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X16; - else if (pCreateInfo->maxAnisotropy >= 8.0f) - word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X8; - else if (pCreateInfo->maxAnisotropy >= 4.0f) - word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X4; - else if (pCreateInfo->maxAnisotropy >= 2.0f) - word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X2; - } - - if (PVR_HAS_QUIRK(&device->pdevice->dev_info, 51025) && - pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST) { - /* When MIPMAP_MODE_NEAREST is enabled, the LOD level should be - * selected by adding 0.5 and then truncating the input LOD value. - * This hardware adds the 0.5 bias before clamping against - * lodmin/lodmax, while Vulkan specifies the bias to be added after - * clamping. We compensate for this difference by adding the 0.5 - * bias to the LOD bounds, too. - */ - lod_rounding_bias = 0.5f; - } else { - lod_rounding_bias = 0.0f; - } - - min_lod = pCreateInfo->minLod + lod_rounding_bias; - word.minlod = util_unsigned_fixed(CLAMP(min_lod, 0.0f, lod_clamp_max), - ROGUE_TEXSTATE_CLAMP_FRACTIONAL_BITS); - - max_lod = pCreateInfo->maxLod + lod_rounding_bias; - word.maxlod = util_unsigned_fixed(CLAMP(max_lod, 0.0f, lod_clamp_max), - ROGUE_TEXSTATE_CLAMP_FRACTIONAL_BITS); - - word.bordercolor_index = sampler->border_color_table_index; - - if (pCreateInfo->unnormalizedCoordinates) - word.non_normalized_coords = true; - } - - pvr_csb_pack (&sampler->descriptor.words[1], TEXSTATE_SAMPLER_WORD1, word) {} - - /* Setup gather sampler. */ - - struct ROGUE_TEXSTATE_SAMPLER_WORD0 word0; - ROGUE_TEXSTATE_SAMPLER_WORD0_unpack(&sampler->descriptor.words[0], &word0); - word0.mipfilter = false; - word0.minfilter = ROGUE_TEXSTATE_FILTER_LINEAR; - word0.magfilter = ROGUE_TEXSTATE_FILTER_LINEAR; - ROGUE_TEXSTATE_SAMPLER_WORD0_pack(&sampler->descriptor.gather_words[0], - &word0); - - memcpy(&sampler->descriptor.gather_words[1], - &sampler->descriptor.words[1], - sizeof(sampler->descriptor.words[1])); - - *pSampler = pvr_sampler_to_handle(sampler); - - return VK_SUCCESS; - -err_free_sampler: - vk_object_free(&device->vk, pAllocator, sampler); - -err_out: - return result; -} - -void pvr_DestroySampler(VkDevice _device, - VkSampler _sampler, - const VkAllocationCallbacks *pAllocator) -{ - VK_FROM_HANDLE(pvr_device, device, _device); - VK_FROM_HANDLE(pvr_sampler, sampler, _sampler); - - if (!sampler) - return; - - pvr_border_color_table_release_entry(&device->border_color_table, - sampler->border_color_table_index); - - vk_sampler_destroy(&device->vk, pAllocator, &sampler->vk); -} - void pvr_GetBufferMemoryRequirements2( VkDevice _device, const VkBufferMemoryRequirementsInfo2 *pInfo, diff --git a/src/imagination/vulkan/pvr_sampler.c b/src/imagination/vulkan/pvr_sampler.c new file mode 100644 index 00000000000..c78489857f7 --- /dev/null +++ b/src/imagination/vulkan/pvr_sampler.c @@ -0,0 +1,235 @@ +/* + * Copyright © 2022 Imagination Technologies Ltd. + * + * based in part on anv driver which is: + * Copyright © 2015 Intel Corporation + * + * based in part on radv driver which is: + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * SPDX-License-Identifier: MIT + */ + +#include "pvr_sampler.h" + +#include "vk_log.h" + +#include "pvr_device.h" +#include "pvr_entrypoints.h" +#include "pvr_physical_device.h" + +static uint32_t +pvr_sampler_get_hw_filter_from_vk(const struct pvr_device_info *dev_info, + VkFilter filter) +{ + switch (filter) { + case VK_FILTER_NEAREST: + return ROGUE_TEXSTATE_FILTER_POINT; + case VK_FILTER_LINEAR: + return ROGUE_TEXSTATE_FILTER_LINEAR; + default: + UNREACHABLE("Unknown filter type."); + } +} + +static uint32_t +pvr_sampler_get_hw_addr_mode_from_vk(VkSamplerAddressMode addr_mode) +{ + switch (addr_mode) { + case VK_SAMPLER_ADDRESS_MODE_REPEAT: + return ROGUE_TEXSTATE_ADDRMODE_REPEAT; + case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + return ROGUE_TEXSTATE_ADDRMODE_FLIP; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + return ROGUE_TEXSTATE_ADDRMODE_CLAMP_TO_EDGE; + case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: + return ROGUE_TEXSTATE_ADDRMODE_FLIP_ONCE_THEN_CLAMP; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + return ROGUE_TEXSTATE_ADDRMODE_CLAMP_TO_BORDER; + default: + UNREACHABLE("Invalid sampler address mode."); + } +} + +VkResult pvr_CreateSampler(VkDevice _device, + const VkSamplerCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSampler *pSampler) +{ + VK_FROM_HANDLE(pvr_device, device, _device); + struct pvr_sampler *sampler; + float lod_rounding_bias; + VkFilter min_filter; + VkFilter mag_filter; + VkResult result; + float min_lod; + float max_lod; + + sampler = + vk_sampler_create(&device->vk, pCreateInfo, pAllocator, sizeof(*sampler)); + if (!sampler) { + result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + goto err_out; + } + + mag_filter = pCreateInfo->magFilter; + min_filter = pCreateInfo->minFilter; + + result = pvr_border_color_table_get_or_create_entry( + device, + sampler, + &device->border_color_table, + &sampler->border_color_table_index); + if (result != VK_SUCCESS) + goto err_free_sampler; + + if (PVR_HAS_QUIRK(&device->pdevice->dev_info, 51025)) { + /* The min/mag filters may need adjustment here, the GPU should decide + * which of the two filters to use based on the clamped LOD value: LOD + * <= 0 implies magnification, while LOD > 0 implies minification. + * + * As a workaround, we override magFilter with minFilter if we know that + * the magnification filter will never be used due to clamping anyway + * (i.e. minLod > 0). Conversely, we override minFilter with magFilter + * if maxLod <= 0. + */ + if (pCreateInfo->minLod > 0.0f) { + /* The clamped LOD will always be positive => always minify. */ + mag_filter = pCreateInfo->minFilter; + } + + if (pCreateInfo->maxLod <= 0.0f) { + /* The clamped LOD will always be negative or zero => always + * magnify. + */ + min_filter = pCreateInfo->magFilter; + } + } + + if (pCreateInfo->compareEnable) { + sampler->descriptor.meta[PCO_SAMPLER_META_COMPARE_OP] = + pCreateInfo->compareOp; + } else { + sampler->descriptor.meta[PCO_SAMPLER_META_COMPARE_OP] = + VK_COMPARE_OP_NEVER; + } + + pvr_csb_pack (&sampler->descriptor.words[0], TEXSTATE_SAMPLER_WORD0, word) { + const struct pvr_device_info *dev_info = &device->pdevice->dev_info; + const float lod_clamp_max = (float)ROGUE_TEXSTATE_CLAMP_MAX / + (1 << ROGUE_TEXSTATE_CLAMP_FRACTIONAL_BITS); + const float max_dadjust = ((float)(ROGUE_TEXSTATE_DADJUST_MAX_UINT - + ROGUE_TEXSTATE_DADJUST_ZERO_UINT)) / + (1 << ROGUE_TEXSTATE_DADJUST_FRACTIONAL_BITS); + const float min_dadjust = ((float)(ROGUE_TEXSTATE_DADJUST_MIN_UINT - + ROGUE_TEXSTATE_DADJUST_ZERO_UINT)) / + (1 << ROGUE_TEXSTATE_DADJUST_FRACTIONAL_BITS); + + word.magfilter = pvr_sampler_get_hw_filter_from_vk(dev_info, mag_filter); + word.minfilter = pvr_sampler_get_hw_filter_from_vk(dev_info, min_filter); + + if (pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR) + word.mipfilter = true; + + word.addrmode_u = + pvr_sampler_get_hw_addr_mode_from_vk(pCreateInfo->addressModeU); + word.addrmode_v = + pvr_sampler_get_hw_addr_mode_from_vk(pCreateInfo->addressModeV); + word.addrmode_w = + pvr_sampler_get_hw_addr_mode_from_vk(pCreateInfo->addressModeW); + + /* The Vulkan 1.0.205 spec says: + * + * The absolute value of mipLodBias must be less than or equal to + * VkPhysicalDeviceLimits::maxSamplerLodBias. + */ + word.dadjust = + ROGUE_TEXSTATE_DADJUST_ZERO_UINT + + util_signed_fixed( + CLAMP(pCreateInfo->mipLodBias, min_dadjust, max_dadjust), + ROGUE_TEXSTATE_DADJUST_FRACTIONAL_BITS); + + word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_DISABLED; + if (pCreateInfo->anisotropyEnable) { + if (pCreateInfo->maxAnisotropy >= 16.0f) + word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X16; + else if (pCreateInfo->maxAnisotropy >= 8.0f) + word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X8; + else if (pCreateInfo->maxAnisotropy >= 4.0f) + word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X4; + else if (pCreateInfo->maxAnisotropy >= 2.0f) + word.anisoctl = ROGUE_TEXSTATE_ANISOCTL_X2; + } + + if (PVR_HAS_QUIRK(&device->pdevice->dev_info, 51025) && + pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST) { + /* When MIPMAP_MODE_NEAREST is enabled, the LOD level should be + * selected by adding 0.5 and then truncating the input LOD value. + * This hardware adds the 0.5 bias before clamping against + * lodmin/lodmax, while Vulkan specifies the bias to be added after + * clamping. We compensate for this difference by adding the 0.5 + * bias to the LOD bounds, too. + */ + lod_rounding_bias = 0.5f; + } else { + lod_rounding_bias = 0.0f; + } + + min_lod = pCreateInfo->minLod + lod_rounding_bias; + word.minlod = util_unsigned_fixed(CLAMP(min_lod, 0.0f, lod_clamp_max), + ROGUE_TEXSTATE_CLAMP_FRACTIONAL_BITS); + + max_lod = pCreateInfo->maxLod + lod_rounding_bias; + word.maxlod = util_unsigned_fixed(CLAMP(max_lod, 0.0f, lod_clamp_max), + ROGUE_TEXSTATE_CLAMP_FRACTIONAL_BITS); + + word.bordercolor_index = sampler->border_color_table_index; + + if (pCreateInfo->unnormalizedCoordinates) + word.non_normalized_coords = true; + } + + pvr_csb_pack (&sampler->descriptor.words[1], TEXSTATE_SAMPLER_WORD1, word) {} + + /* Setup gather sampler. */ + + struct ROGUE_TEXSTATE_SAMPLER_WORD0 word0; + ROGUE_TEXSTATE_SAMPLER_WORD0_unpack(&sampler->descriptor.words[0], &word0); + word0.mipfilter = false; + word0.minfilter = ROGUE_TEXSTATE_FILTER_LINEAR; + word0.magfilter = ROGUE_TEXSTATE_FILTER_LINEAR; + ROGUE_TEXSTATE_SAMPLER_WORD0_pack(&sampler->descriptor.gather_words[0], + &word0); + + memcpy(&sampler->descriptor.gather_words[1], + &sampler->descriptor.words[1], + sizeof(sampler->descriptor.words[1])); + + *pSampler = pvr_sampler_to_handle(sampler); + + return VK_SUCCESS; + +err_free_sampler: + vk_object_free(&device->vk, pAllocator, sampler); + +err_out: + return result; +} + +void pvr_DestroySampler(VkDevice _device, + VkSampler _sampler, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(pvr_device, device, _device); + VK_FROM_HANDLE(pvr_sampler, sampler, _sampler); + + if (!sampler) + return; + + pvr_border_color_table_release_entry(&device->border_color_table, + sampler->border_color_table_index); + + vk_sampler_destroy(&device->vk, pAllocator, &sampler->vk); +} + diff --git a/src/imagination/vulkan/pvr_sampler.h b/src/imagination/vulkan/pvr_sampler.h new file mode 100644 index 00000000000..4a797a3fc29 --- /dev/null +++ b/src/imagination/vulkan/pvr_sampler.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2022 Imagination Technologies Ltd. + * + * based in part on anv driver which is: + * Copyright © 2015 Intel Corporation + * + * based in part on radv driver which is: + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * SPDX-License-Identifier: MIT + */ + +#ifndef PVR_SAMPLER_H +#define PVR_SAMPLER_H + +#include + +#include "vk_sampler.h" + +#include "hwdef/rogue_hw_defs.h" + +#include "pco/pco_data.h" + +#include "pvr_common.h" + +struct pvr_sampler { + struct vk_sampler vk; + struct pvr_sampler_descriptor descriptor; + uint32_t border_color_table_index; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_sampler, + vk.base, + VkSampler, + VK_OBJECT_TYPE_SAMPLER) + +#endif /* PVR_SAMPLER_H */ diff --git a/src/imagination/vulkan/pvr_usc.c b/src/imagination/vulkan/pvr_usc.c index eff0947145d..4f52d82d43b 100644 --- a/src/imagination/vulkan/pvr_usc.c +++ b/src/imagination/vulkan/pvr_usc.c @@ -24,6 +24,7 @@ #include "pvr_formats.h" #include "pvr_hw_pass.h" #include "pvr_pass.h" +#include "pvr_sampler.h" #include "pvr_usc.h" #include "util/macros.h"