pvr: factor out pvr_sampler

Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38352>
This commit is contained in:
Erik Faye-Lund 2025-11-03 17:19:04 +01:00
parent cf08978985
commit e7fb4a9948
8 changed files with 277 additions and 225 deletions

View file

@ -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',

View file

@ -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"

View file

@ -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 */

View file

@ -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"

View file

@ -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,

View file

@ -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);
}

View file

@ -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 <stdint.h>
#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 */

View file

@ -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"