anv/pipeline: Add skeleton support for spilling to bindless

If the number of surfaces or samplers exceeds what we can put in a
table, we will want to spill out to bindless.  There is no bindless
support yet but this gets us the basic framework that will be used by
later commits.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
This commit is contained in:
Jason Ekstrand
2019-02-25 13:59:07 -06:00
committed by Jason Ekstrand
parent a7d4871846
commit 146deec9ef
4 changed files with 122 additions and 27 deletions

View File

@@ -125,22 +125,60 @@ anv_descriptor_type_size(const struct anv_physical_device *pdevice,
return anv_descriptor_data_size(anv_descriptor_data_for_type(pdevice, type)); return anv_descriptor_data_size(anv_descriptor_data_for_type(pdevice, type));
} }
static bool
anv_descriptor_data_supports_bindless(const struct anv_physical_device *pdevice,
enum anv_descriptor_data data,
bool sampler)
{
return false;
}
bool
anv_descriptor_supports_bindless(const struct anv_physical_device *pdevice,
const struct anv_descriptor_set_binding_layout *binding,
bool sampler)
{
return anv_descriptor_data_supports_bindless(pdevice, binding->data,
sampler);
}
bool
anv_descriptor_requires_bindless(const struct anv_physical_device *pdevice,
const struct anv_descriptor_set_binding_layout *binding,
bool sampler)
{
if (pdevice->always_use_bindless)
return anv_descriptor_supports_bindless(pdevice, binding, sampler);
return false;
}
void anv_GetDescriptorSetLayoutSupport( void anv_GetDescriptorSetLayoutSupport(
VkDevice device, VkDevice _device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
VkDescriptorSetLayoutSupport* pSupport) VkDescriptorSetLayoutSupport* pSupport)
{ {
ANV_FROM_HANDLE(anv_device, device, _device);
const struct anv_physical_device *pdevice =
&device->instance->physicalDevice;
uint32_t surface_count[MESA_SHADER_STAGES] = { 0, }; uint32_t surface_count[MESA_SHADER_STAGES] = { 0, };
for (uint32_t b = 0; b < pCreateInfo->bindingCount; b++) { for (uint32_t b = 0; b < pCreateInfo->bindingCount; b++) {
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[b]; const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[b];
enum anv_descriptor_data desc_data =
anv_descriptor_data_for_type(pdevice, binding->descriptorType);
switch (binding->descriptorType) { switch (binding->descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLER:
/* There is no real limit on samplers */ /* There is no real limit on samplers */
break; break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
if (anv_descriptor_data_supports_bindless(pdevice, desc_data, false))
break;
if (binding->pImmutableSamplers) { if (binding->pImmutableSamplers) {
for (uint32_t i = 0; i < binding->descriptorCount; i++) { for (uint32_t i = 0; i < binding->descriptorCount; i++) {
ANV_FROM_HANDLE(anv_sampler, sampler, ANV_FROM_HANDLE(anv_sampler, sampler,
@@ -155,6 +193,9 @@ void anv_GetDescriptorSetLayoutSupport(
break; break;
default: default:
if (anv_descriptor_data_supports_bindless(pdevice, desc_data, false))
break;
anv_foreach_stage(s, binding->stageFlags) anv_foreach_stage(s, binding->stageFlags)
surface_count[s] += binding->descriptorCount; surface_count[s] += binding->descriptorCount;
break; break;

View File

@@ -276,6 +276,8 @@ anv_physical_device_init_uuids(struct anv_physical_device *device)
_mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len); _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
_mesa_sha1_update(&sha1_ctx, &device->chipset_id, _mesa_sha1_update(&sha1_ctx, &device->chipset_id,
sizeof(device->chipset_id)); sizeof(device->chipset_id));
_mesa_sha1_update(&sha1_ctx, &device->always_use_bindless,
sizeof(device->always_use_bindless));
_mesa_sha1_final(&sha1_ctx, sha1); _mesa_sha1_final(&sha1_ctx, sha1);
memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE); memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
@@ -451,6 +453,10 @@ anv_physical_device_init(struct anv_physical_device *device,
device->has_context_isolation = device->has_context_isolation =
anv_gem_get_param(fd, I915_PARAM_HAS_CONTEXT_ISOLATION); anv_gem_get_param(fd, I915_PARAM_HAS_CONTEXT_ISOLATION);
device->always_use_bindless =
env_var_as_boolean("ANV_ALWAYS_BINDLESS", false);
/* Starting with Gen10, the timestamp frequency of the command streamer may /* Starting with Gen10, the timestamp frequency of the command streamer may
* vary from one part to another. We can query the value from the kernel. * vary from one part to another. We can query the value from the kernel.
*/ */

View File

@@ -26,6 +26,12 @@
#include "nir/nir_builder.h" #include "nir/nir_builder.h"
#include "compiler/brw_nir.h" #include "compiler/brw_nir.h"
/* Sampler tables don't actually have a maximum size but we pick one just so
* that we don't end up emitting too much state on-the-fly.
*/
#define MAX_SAMPLER_TABLE_SIZE 128
#define BINDLESS_OFFSET 255
struct apply_pipeline_layout_state { struct apply_pipeline_layout_state {
const struct anv_physical_device *pdevice; const struct anv_physical_device *pdevice;
@@ -600,11 +606,21 @@ anv_nir_apply_pipeline_layout(const struct anv_physical_device *pdevice,
&layout->set[set].layout->binding[b]; &layout->set[set].layout->binding[b];
/* Do a fixed-point calculation to generate a score based on the /* Do a fixed-point calculation to generate a score based on the
* number of uses and the binding array size. * number of uses and the binding array size. We shift by 7 instead
* of 8 because we're going to use the top bit below to make
* everything which does not support bindless super higher priority
* than things which do.
*/ */
uint16_t score = ((uint16_t)state.set[set].use_count[b] << 7) / uint16_t score = ((uint16_t)state.set[set].use_count[b] << 7) /
binding->array_size; binding->array_size;
/* If the descriptor type doesn't support bindless then put it at the
* beginning so we guarantee it gets a slot.
*/
if (!anv_descriptor_supports_bindless(pdevice, binding, true) ||
!anv_descriptor_supports_bindless(pdevice, binding, false))
score |= 1 << 15;
infos[used_binding_count++] = (struct binding_info) { infos[used_binding_count++] = (struct binding_info) {
.set = set, .set = set,
.binding = b, .binding = b,
@@ -624,37 +640,57 @@ anv_nir_apply_pipeline_layout(const struct anv_physical_device *pdevice,
struct anv_descriptor_set_binding_layout *binding = struct anv_descriptor_set_binding_layout *binding =
&layout->set[set].layout->binding[b]; &layout->set[set].layout->binding[b];
const uint32_t array_size = binding->array_size;
if (binding->data & ANV_DESCRIPTOR_SURFACE_STATE) { if (binding->data & ANV_DESCRIPTOR_SURFACE_STATE) {
state.set[set].surface_offsets[b] = map->surface_count; if (map->surface_count + array_size > MAX_BINDING_TABLE_SIZE ||
struct anv_sampler **samplers = binding->immutable_samplers; anv_descriptor_requires_bindless(pdevice, binding, false)) {
for (unsigned i = 0; i < binding->array_size; i++) { /* If this descriptor doesn't fit in the binding table or if it
uint8_t planes = samplers ? samplers[i]->n_planes : 1; * requires bindless for some reason, flag it as bindless.
for (uint8_t p = 0; p < planes; p++) { */
map->surface_to_descriptor[map->surface_count++] = assert(anv_descriptor_supports_bindless(pdevice, binding, false));
(struct anv_pipeline_binding) { state.set[set].surface_offsets[b] = BINDLESS_OFFSET;
.set = set, } else {
.binding = b, state.set[set].surface_offsets[b] = map->surface_count;
.index = i, struct anv_sampler **samplers = binding->immutable_samplers;
.plane = p, for (unsigned i = 0; i < binding->array_size; i++) {
}; uint8_t planes = samplers ? samplers[i]->n_planes : 1;
for (uint8_t p = 0; p < planes; p++) {
map->surface_to_descriptor[map->surface_count++] =
(struct anv_pipeline_binding) {
.set = set,
.binding = b,
.index = i,
.plane = p,
};
}
} }
} }
assert(map->surface_count <= MAX_BINDING_TABLE_SIZE);
} }
assert(map->surface_count <= MAX_BINDING_TABLE_SIZE);
if (binding->data & ANV_DESCRIPTOR_SAMPLER_STATE) { if (binding->data & ANV_DESCRIPTOR_SAMPLER_STATE) {
state.set[set].sampler_offsets[b] = map->sampler_count; if (map->sampler_count + array_size > MAX_SAMPLER_TABLE_SIZE ||
struct anv_sampler **samplers = binding->immutable_samplers; anv_descriptor_requires_bindless(pdevice, binding, true)) {
for (unsigned i = 0; i < binding->array_size; i++) { /* If this descriptor doesn't fit in the binding table or if it
uint8_t planes = samplers ? samplers[i]->n_planes : 1; * requires bindless for some reason, flag it as bindless.
for (uint8_t p = 0; p < planes; p++) { */
map->sampler_to_descriptor[map->sampler_count++] = assert(anv_descriptor_supports_bindless(pdevice, binding, true));
(struct anv_pipeline_binding) { state.set[set].sampler_offsets[b] = BINDLESS_OFFSET;
.set = set, } else {
.binding = b, state.set[set].sampler_offsets[b] = map->sampler_count;
.index = i, struct anv_sampler **samplers = binding->immutable_samplers;
.plane = p, for (unsigned i = 0; i < binding->array_size; i++) {
}; uint8_t planes = samplers ? samplers[i]->n_planes : 1;
for (uint8_t p = 0; p < planes; p++) {
map->sampler_to_descriptor[map->sampler_count++] =
(struct anv_pipeline_binding) {
.set = set,
.binding = b,
.index = i,
.plane = p,
};
}
} }
} }
} }
@@ -676,6 +712,9 @@ anv_nir_apply_pipeline_layout(const struct anv_physical_device *pdevice,
if (state.set[set].use_count[binding] == 0) if (state.set[set].use_count[binding] == 0)
continue; continue;
if (state.set[set].surface_offsets[binding] >= MAX_BINDING_TABLE_SIZE)
continue;
struct anv_pipeline_binding *pipe_binding = struct anv_pipeline_binding *pipe_binding =
&map->surface_to_descriptor[state.set[set].surface_offsets[binding]]; &map->surface_to_descriptor[state.set[set].surface_offsets[binding]];
for (unsigned i = 0; i < array_size; i++) { for (unsigned i = 0; i < array_size; i++) {

View File

@@ -949,6 +949,7 @@ struct anv_physical_device {
bool has_context_priority; bool has_context_priority;
bool use_softpin; bool use_softpin;
bool has_context_isolation; bool has_context_isolation;
bool always_use_bindless;
struct anv_device_extension_table supported_extensions; struct anv_device_extension_table supported_extensions;
@@ -1565,6 +1566,14 @@ unsigned anv_descriptor_size(const struct anv_descriptor_set_binding_layout *lay
unsigned anv_descriptor_type_size(const struct anv_physical_device *pdevice, unsigned anv_descriptor_type_size(const struct anv_physical_device *pdevice,
VkDescriptorType type); VkDescriptorType type);
bool anv_descriptor_supports_bindless(const struct anv_physical_device *pdevice,
const struct anv_descriptor_set_binding_layout *binding,
bool sampler);
bool anv_descriptor_requires_bindless(const struct anv_physical_device *pdevice,
const struct anv_descriptor_set_binding_layout *binding,
bool sampler);
struct anv_descriptor_set_layout { struct anv_descriptor_set_layout {
/* Descriptor set layouts can be destroyed at almost any time */ /* Descriptor set layouts can be destroyed at almost any time */
uint32_t ref_cnt; uint32_t ref_cnt;