1664 lines
61 KiB
C
1664 lines
61 KiB
C
/*
|
|
* Copyright © 2022 Imagination Technologies Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include "hwdef/rogue_hw_utils.h"
|
|
#include "pvr_bo.h"
|
|
#include "pvr_private.h"
|
|
#include "pvr_types.h"
|
|
#include "util/compiler.h"
|
|
#include "util/list.h"
|
|
#include "util/log.h"
|
|
#include "util/macros.h"
|
|
#include "vk_alloc.h"
|
|
#include "vk_log.h"
|
|
#include "vk_object.h"
|
|
#include "vk_util.h"
|
|
|
|
#if defined(DEBUG)
|
|
static const struct {
|
|
const char *raw;
|
|
const char *primary;
|
|
const char *secondary;
|
|
const char *primary_dynamic;
|
|
const char *secondary_dynamic;
|
|
} stage_names[] = {
|
|
{ "Vertex",
|
|
"Vertex Primary",
|
|
"Vertex Secondary",
|
|
"Vertex Dynamic Primary",
|
|
"Vertex Dynamic Secondary" },
|
|
{ "Fragment",
|
|
"Fragment Primary",
|
|
"Fragment Secondary",
|
|
"Fragment Dynamic Primary",
|
|
"Fragment Dynamic Secondary" },
|
|
{ "Compute",
|
|
"Compute Primary",
|
|
"Compute Secondary",
|
|
"Compute Dynamic Primary",
|
|
"Compute Dynamic Secondary" },
|
|
};
|
|
|
|
static const char *descriptor_names[] = { "VK SAMPLER",
|
|
"VK COMBINED_IMAGE_SAMPLER",
|
|
"VK SAMPLED_IMAGE",
|
|
"VK STORAGE_IMAGE",
|
|
"VK UNIFORM_TEXEL_BUFFER",
|
|
"VK STORAGE_TEXEL_BUFFER",
|
|
"VK UNIFORM_BUFFER",
|
|
"VK STORAGE_BUFFER",
|
|
"VK UNIFORM_BUFFER_DYNAMIC",
|
|
"VK STORAGE_BUFFER_DYNAMIC",
|
|
"VK INPUT_ATTACHMENT" };
|
|
#endif
|
|
|
|
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE 0U
|
|
#define PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYBASE 2U
|
|
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYSTRIDE \
|
|
(PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE + \
|
|
PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYBASE)
|
|
#define PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYSTRIDE 1U
|
|
|
|
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info) \
|
|
(PVR_HAS_FEATURE(dev_info, tpu_array_textures) \
|
|
? (0) \
|
|
: PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYSTRIDE + \
|
|
PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYSTRIDE)
|
|
|
|
#define PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYMAXINDEX 1U
|
|
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info) \
|
|
(PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info) + \
|
|
PVR_DESC_IMAGE_SECONDARY_SIZE_ARRAYMAXINDEX)
|
|
#define PVR_DESC_IMAGE_SECONDARY_SIZE_WIDTH 1U
|
|
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info) \
|
|
(PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info) + \
|
|
PVR_DESC_IMAGE_SECONDARY_SIZE_WIDTH)
|
|
#define PVR_DESC_IMAGE_SECONDARY_SIZE_HEIGHT 1U
|
|
#define PVR_DESC_IMAGE_SECONDARY_OFFSET_DEPTH(dev_info) \
|
|
(PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info) + \
|
|
PVR_DESC_IMAGE_SECONDARY_SIZE_HEIGHT)
|
|
#define PVR_DESC_IMAGE_SECONDARY_SIZE_DEPTH 1U
|
|
#define PVR_DESC_IMAGE_SECONDARY_TOTAL_SIZE(dev_info) \
|
|
(PVR_DESC_IMAGE_SECONDARY_OFFSET_DEPTH(dev_info) + \
|
|
PVR_DESC_IMAGE_SECONDARY_SIZE_DEPTH)
|
|
|
|
static void pvr_descriptor_size_info_init(
|
|
const struct pvr_device *device,
|
|
VkDescriptorType type,
|
|
struct pvr_descriptor_size_info *const size_info_out)
|
|
{
|
|
/* UINT_MAX is a place holder. These values will be filled by calling the
|
|
* init function, and set appropriately based on device features.
|
|
*/
|
|
static const struct pvr_descriptor_size_info template_size_infos[] = {
|
|
/* VK_DESCRIPTOR_TYPE_SAMPLER */
|
|
{ PVR_SAMPLER_DESCRIPTOR_SIZE, 0, 4 },
|
|
/* VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER */
|
|
{ PVR_IMAGE_DESCRIPTOR_SIZE + PVR_SAMPLER_DESCRIPTOR_SIZE, UINT_MAX, 4 },
|
|
/* VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE */
|
|
{ 4, UINT_MAX, 4 },
|
|
/* VK_DESCRIPTOR_TYPE_STORAGE_IMAGE */
|
|
{ 4, UINT_MAX, 4 },
|
|
/* VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER */
|
|
{ 4, UINT_MAX, 4 },
|
|
/* VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER */
|
|
{ 4, UINT_MAX, 4 },
|
|
/* VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER */
|
|
{ 2, UINT_MAX, 2 },
|
|
/* VK_DESCRIPTOR_TYPE_STORAGE_BUFFER */
|
|
{ 2, 1, 2 },
|
|
/* VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC */
|
|
{ 2, UINT_MAX, 2 },
|
|
/* VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC */
|
|
{ 2, 1, 2 },
|
|
/* VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT */
|
|
{ 8, UINT_MAX, 4 }
|
|
};
|
|
|
|
*size_info_out = template_size_infos[type];
|
|
|
|
switch (type) {
|
|
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
|
size_info_out->secondary =
|
|
PVR_DESC_IMAGE_SECONDARY_TOTAL_SIZE(&device->pdevice->dev_info);
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
|
size_info_out->secondary = (uint32_t)device->features.robustBufferAccess;
|
|
break;
|
|
|
|
default:
|
|
unreachable("Unknown descriptor type");
|
|
}
|
|
}
|
|
|
|
static bool pvr_stage_matches_vk_flags(enum pvr_stage_allocation pvr_stage,
|
|
VkShaderStageFlags flags)
|
|
{
|
|
VkShaderStageFlags flags_per_stage;
|
|
|
|
switch (pvr_stage) {
|
|
case PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY:
|
|
flags_per_stage = VK_SHADER_STAGE_VERTEX_BIT |
|
|
VK_SHADER_STAGE_GEOMETRY_BIT;
|
|
break;
|
|
case PVR_STAGE_ALLOCATION_FRAGMENT:
|
|
flags_per_stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
break;
|
|
case PVR_STAGE_ALLOCATION_COMPUTE:
|
|
flags_per_stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
|
break;
|
|
default:
|
|
unreachable("Unrecognized allocation stage.");
|
|
}
|
|
|
|
return !!(flags_per_stage & flags);
|
|
}
|
|
|
|
/* If allocator == NULL, the internal one will be used. */
|
|
static struct pvr_descriptor_set_layout *
|
|
pvr_descriptor_set_layout_allocate(struct pvr_device *device,
|
|
const VkAllocationCallbacks *allocator,
|
|
uint32_t binding_count,
|
|
uint32_t immutable_sampler_count,
|
|
uint32_t supported_descriptors_count)
|
|
{
|
|
struct pvr_descriptor_set_layout_binding *bindings;
|
|
struct pvr_descriptor_set_layout *layout;
|
|
__typeof__(layout->per_stage_descriptor_count) counts;
|
|
const struct pvr_sampler **immutable_samplers;
|
|
|
|
VK_MULTIALLOC(ma);
|
|
vk_multialloc_add(&ma, &layout, __typeof__(*layout), 1);
|
|
vk_multialloc_add(&ma, &bindings, __typeof__(*bindings), binding_count);
|
|
vk_multialloc_add(&ma,
|
|
&immutable_samplers,
|
|
__typeof__(*immutable_samplers),
|
|
immutable_sampler_count);
|
|
|
|
for (uint32_t stage = 0; stage < ARRAY_SIZE(counts); stage++) {
|
|
vk_multialloc_add(&ma,
|
|
&counts[stage],
|
|
__typeof__(*counts[0]),
|
|
supported_descriptors_count);
|
|
}
|
|
|
|
/* pvr_CreateDescriptorSetLayout() relies on this being zero allocated. */
|
|
if (!vk_multialloc_zalloc2(&ma,
|
|
&device->vk.alloc,
|
|
allocator,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)) {
|
|
return NULL;
|
|
}
|
|
|
|
layout->bindings = bindings;
|
|
layout->immutable_samplers = immutable_samplers;
|
|
|
|
memcpy(&layout->per_stage_descriptor_count, &counts, sizeof(counts));
|
|
|
|
vk_object_base_init(&device->vk,
|
|
&layout->base,
|
|
VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT);
|
|
|
|
return layout;
|
|
}
|
|
|
|
/* If allocator == NULL, the internal one will be used. */
|
|
static void
|
|
pvr_descriptor_set_layout_free(struct pvr_device *device,
|
|
const VkAllocationCallbacks *allocator,
|
|
struct pvr_descriptor_set_layout *layout)
|
|
{
|
|
vk_object_base_finish(&layout->base);
|
|
vk_free2(&device->vk.alloc, allocator, layout);
|
|
}
|
|
|
|
static int pvr_binding_compare(const void *a, const void *b)
|
|
{
|
|
uint32_t binding_a = ((VkDescriptorSetLayoutBinding *)a)->binding;
|
|
uint32_t binding_b = ((VkDescriptorSetLayoutBinding *)b)->binding;
|
|
|
|
if (binding_a < binding_b)
|
|
return -1;
|
|
|
|
if (binding_a > binding_b)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* If allocator == NULL, the internal one will be used. */
|
|
static VkDescriptorSetLayoutBinding *
|
|
pvr_create_sorted_bindings(struct pvr_device *device,
|
|
const VkAllocationCallbacks *allocator,
|
|
const VkDescriptorSetLayoutBinding *bindings,
|
|
uint32_t binding_count)
|
|
{
|
|
VkDescriptorSetLayoutBinding *sorted_bindings =
|
|
vk_alloc2(&device->vk.alloc,
|
|
allocator,
|
|
binding_count * sizeof(*sorted_bindings),
|
|
8,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!sorted_bindings)
|
|
return NULL;
|
|
|
|
memcpy(sorted_bindings, bindings, binding_count * sizeof(*sorted_bindings));
|
|
|
|
qsort(sorted_bindings,
|
|
binding_count,
|
|
sizeof(*sorted_bindings),
|
|
pvr_binding_compare);
|
|
|
|
return sorted_bindings;
|
|
}
|
|
|
|
struct pvr_register_usage {
|
|
uint32_t primary;
|
|
uint32_t primary_dynamic;
|
|
uint32_t secondary;
|
|
uint32_t secondary_dynamic;
|
|
};
|
|
|
|
static void pvr_setup_in_memory_layout_sizes(
|
|
struct pvr_descriptor_set_layout *layout,
|
|
const struct pvr_register_usage reg_usage[PVR_STAGE_ALLOCATION_COUNT])
|
|
{
|
|
for (uint32_t stage = 0;
|
|
stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage);
|
|
stage++) {
|
|
layout->total_size_in_dwords = ALIGN_POT(layout->total_size_in_dwords, 4);
|
|
|
|
layout->memory_layout_in_dwords_per_stage[stage].primary_offset =
|
|
layout->total_size_in_dwords;
|
|
layout->memory_layout_in_dwords_per_stage[stage].primary_size =
|
|
reg_usage[stage].primary;
|
|
|
|
layout->total_size_in_dwords += reg_usage[stage].primary;
|
|
layout->total_size_in_dwords = ALIGN_POT(layout->total_size_in_dwords, 4);
|
|
|
|
layout->memory_layout_in_dwords_per_stage[stage].secondary_offset =
|
|
layout->total_size_in_dwords;
|
|
layout->memory_layout_in_dwords_per_stage[stage].secondary_size =
|
|
reg_usage[stage].secondary;
|
|
|
|
layout->total_size_in_dwords += reg_usage[stage].secondary;
|
|
|
|
layout->memory_layout_in_dwords_per_stage[stage].primary_dynamic_size =
|
|
reg_usage[stage].primary_dynamic;
|
|
layout->memory_layout_in_dwords_per_stage[stage].secondary_dynamic_size =
|
|
reg_usage[stage].secondary_dynamic;
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
static void
|
|
pvr_dump_in_memory_layout_sizes(const struct pvr_descriptor_set_layout *layout)
|
|
{
|
|
mesa_logd("=== SET LAYOUT ===");
|
|
mesa_logd("----------------------------------------------");
|
|
mesa_logd(" in memory:");
|
|
mesa_logd("----------------------------------------------");
|
|
|
|
for (uint32_t stage = 0;
|
|
stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage);
|
|
stage++) {
|
|
mesa_logd(
|
|
"| %-18s @ %04u |",
|
|
stage_names[stage].primary,
|
|
layout->memory_layout_in_dwords_per_stage[stage].primary_offset);
|
|
mesa_logd("----------------------------------------------");
|
|
|
|
/* Print primaries. */
|
|
for (uint32_t i = 0; i < layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&layout->bindings[i];
|
|
|
|
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
|
|
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| %s %04u | %-26s[%3u] |",
|
|
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
|
|
binding->per_stage_offset_in_dwords[stage].primary,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
}
|
|
|
|
/* Print dynamic primaries. */
|
|
for (uint32_t i = 0; i < layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&layout->bindings[i];
|
|
|
|
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
|
|
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| * %s %04u | %-26s[%3u] |",
|
|
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
|
|
binding->per_stage_offset_in_dwords[stage].primary,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
}
|
|
|
|
mesa_logd("----------------------------------------------");
|
|
mesa_logd(
|
|
"| %-18s @ %04u |",
|
|
stage_names[stage].secondary,
|
|
layout->memory_layout_in_dwords_per_stage[stage].secondary_offset);
|
|
mesa_logd("----------------------------------------------");
|
|
|
|
/* Print secondaries. */
|
|
for (uint32_t i = 0; i < layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&layout->bindings[i];
|
|
|
|
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
|
|
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| %s %04u | %-26s[%3u] |",
|
|
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
|
|
binding->per_stage_offset_in_dwords[stage].secondary,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
}
|
|
|
|
/* Print dynamic secondaries. */
|
|
for (uint32_t i = 0; i < layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&layout->bindings[i];
|
|
|
|
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
|
|
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| * %s %04u | %-26s[%3u] |",
|
|
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
|
|
binding->per_stage_offset_in_dwords[stage].secondary,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
}
|
|
|
|
mesa_logd("==============================================");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
VkResult pvr_CreateDescriptorSetLayout(
|
|
VkDevice _device,
|
|
const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkDescriptorSetLayout *pSetLayout)
|
|
{
|
|
/* Used to accumulate sizes and set each descriptor's offsets per stage. */
|
|
struct pvr_register_usage reg_usage[PVR_STAGE_ALLOCATION_COUNT] = { 0 };
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
struct pvr_descriptor_set_layout *layout;
|
|
VkDescriptorSetLayoutBinding *bindings;
|
|
uint32_t immutable_sampler_count;
|
|
|
|
assert(pCreateInfo->sType ==
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
|
|
|
|
vk_foreach_struct_const (ext, pCreateInfo->pNext) {
|
|
pvr_debug_ignored_stype(ext->sType);
|
|
}
|
|
|
|
/* TODO: Add support for push descriptors. */
|
|
|
|
if (pCreateInfo->bindingCount == 0) {
|
|
layout = pvr_descriptor_set_layout_allocate(device, pAllocator, 0, 0, 0);
|
|
if (!layout)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
*pSetLayout = pvr_descriptor_set_layout_to_handle(layout);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
/* TODO: Instead of sorting, maybe do what anvil does? */
|
|
bindings = pvr_create_sorted_bindings(device,
|
|
pAllocator,
|
|
pCreateInfo->pBindings,
|
|
pCreateInfo->bindingCount);
|
|
if (!bindings)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
immutable_sampler_count = 0;
|
|
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
|
|
/* From the Vulkan 1.1.97 spec for VkDescriptorSetLayoutBinding:
|
|
*
|
|
* "If descriptorType specifies a VK_DESCRIPTOR_TYPE_SAMPLER or
|
|
* VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type descriptor, then
|
|
* pImmutableSamplers can be used to initialize a set of immutable
|
|
* samplers. [...] If descriptorType is not one of these descriptor
|
|
* types, then pImmutableSamplers is ignored.
|
|
*
|
|
* We need to be careful here and only parse pImmutableSamplers if we
|
|
* have one of the right descriptor types.
|
|
*/
|
|
const VkDescriptorType descriptor_type = bindings[i].descriptorType;
|
|
if ((descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
|
|
descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
|
|
bindings[i].pImmutableSamplers)
|
|
immutable_sampler_count += bindings[i].descriptorCount;
|
|
}
|
|
|
|
/* From the Vulkan 1.2.190 spec for VkDescriptorSetLayoutCreateInfo:
|
|
*
|
|
* "The VkDescriptorSetLayoutBinding::binding members of the elements
|
|
* of the pBindings array must each have different values."
|
|
*
|
|
* So we don't worry about duplicates and just allocate for bindingCount
|
|
* amount of bindings.
|
|
*/
|
|
layout = pvr_descriptor_set_layout_allocate(
|
|
device,
|
|
pAllocator,
|
|
pCreateInfo->bindingCount,
|
|
immutable_sampler_count,
|
|
PVR_PIPELINE_LAYOUT_SUPPORTED_DESCRIPTOR_TYPE_COUNT);
|
|
if (!layout) {
|
|
vk_free2(&device->vk.alloc, pAllocator, bindings);
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
}
|
|
|
|
layout->binding_count = pCreateInfo->bindingCount;
|
|
|
|
for (uint32_t bind_num = 0; bind_num < layout->binding_count; bind_num++) {
|
|
const VkDescriptorSetLayoutBinding *const binding = &bindings[bind_num];
|
|
struct pvr_descriptor_set_layout_binding *const internal_binding =
|
|
&layout->bindings[bind_num];
|
|
VkShaderStageFlags shader_stages = 0;
|
|
|
|
internal_binding->type = binding->descriptorType;
|
|
/* The binding_numbers can be non-contiguous so we ignore the user
|
|
* specified binding numbers and make them contiguous ourselves.
|
|
*/
|
|
internal_binding->binding_number = bind_num;
|
|
|
|
/* From Vulkan spec 1.2.189:
|
|
*
|
|
* "If descriptorCount is zero this binding entry is reserved and the
|
|
* resource must not be accessed from any stage via this binding"
|
|
*
|
|
* So do not use bindings->stageFlags, use shader_stages instead.
|
|
*/
|
|
if (binding->descriptorCount) {
|
|
shader_stages = binding->stageFlags;
|
|
|
|
internal_binding->descriptor_count = binding->descriptorCount;
|
|
internal_binding->descriptor_index = layout->descriptor_count;
|
|
layout->descriptor_count += binding->descriptorCount;
|
|
}
|
|
|
|
switch (binding->descriptorType) {
|
|
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
|
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
|
if (binding->pImmutableSamplers && binding->descriptorCount > 0) {
|
|
internal_binding->has_immutable_samplers = true;
|
|
internal_binding->immutable_samplers_index =
|
|
layout->immutable_sampler_count;
|
|
|
|
for (uint32_t j = 0; j < binding->descriptorCount; j++) {
|
|
PVR_FROM_HANDLE(pvr_sampler,
|
|
sampler,
|
|
bindings->pImmutableSamplers[j]);
|
|
const uint32_t next = j + layout->immutable_sampler_count;
|
|
|
|
layout->immutable_samplers[next] = sampler;
|
|
}
|
|
|
|
layout->immutable_sampler_count += binding->descriptorCount;
|
|
}
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
|
layout->dynamic_buffer_count += binding->descriptorCount;
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
|
break;
|
|
|
|
default:
|
|
unreachable("Unknown descriptor type");
|
|
break;
|
|
}
|
|
|
|
if (!shader_stages)
|
|
continue;
|
|
|
|
internal_binding->shader_stages = shader_stages;
|
|
layout->shader_stages |= shader_stages;
|
|
|
|
for (uint32_t stage = 0;
|
|
stage < ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords);
|
|
stage++) {
|
|
const VkDescriptorType descriptor_type = binding->descriptorType;
|
|
|
|
if (!pvr_stage_matches_vk_flags(stage, shader_stages))
|
|
continue;
|
|
|
|
internal_binding->shader_stage_mask |= (1U << stage);
|
|
|
|
/* TODO: Do we have to allocate them at the end? We could speed it
|
|
* by allocating them here if not. */
|
|
/* We allocate dynamics primary and secondaries at the end. */
|
|
if (descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
|
|
descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
|
|
struct pvr_descriptor_size_info size_info;
|
|
|
|
pvr_descriptor_size_info_init(device, descriptor_type, &size_info);
|
|
|
|
STATIC_ASSERT(
|
|
ARRAY_SIZE(reg_usage) ==
|
|
ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords));
|
|
|
|
reg_usage[stage].primary =
|
|
ALIGN_POT(reg_usage[stage].primary, size_info.alignment);
|
|
|
|
internal_binding->per_stage_offset_in_dwords[stage].primary =
|
|
reg_usage[stage].primary;
|
|
reg_usage[stage].primary +=
|
|
size_info.primary * internal_binding->descriptor_count;
|
|
|
|
internal_binding->per_stage_offset_in_dwords[stage].secondary =
|
|
reg_usage[stage].secondary;
|
|
reg_usage[stage].secondary +=
|
|
size_info.secondary * internal_binding->descriptor_count;
|
|
}
|
|
|
|
STATIC_ASSERT(
|
|
ARRAY_SIZE(layout->per_stage_descriptor_count) ==
|
|
ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords));
|
|
|
|
layout->per_stage_descriptor_count[stage][descriptor_type] +=
|
|
internal_binding->descriptor_count;
|
|
}
|
|
}
|
|
|
|
for (uint32_t bind_num = 0; bind_num < layout->binding_count; bind_num++) {
|
|
struct pvr_descriptor_set_layout_binding *const internal_binding =
|
|
&layout->bindings[bind_num];
|
|
const VkDescriptorType descriptor_type = internal_binding->type;
|
|
|
|
if (descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
|
|
descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
for (uint32_t stage = 0;
|
|
stage < ARRAY_SIZE(layout->bindings[0].per_stage_offset_in_dwords);
|
|
stage++) {
|
|
struct pvr_descriptor_size_info size_info;
|
|
const VkShaderStageFlags shader_stages =
|
|
internal_binding->shader_stages;
|
|
|
|
if (!pvr_stage_matches_vk_flags(stage, shader_stages))
|
|
continue;
|
|
|
|
pvr_descriptor_size_info_init(device, descriptor_type, &size_info);
|
|
|
|
/* TODO: align primary like we did with other descriptors? */
|
|
internal_binding->per_stage_offset_in_dwords[stage].primary =
|
|
reg_usage[stage].primary_dynamic;
|
|
reg_usage[stage].primary_dynamic +=
|
|
size_info.primary * internal_binding->descriptor_count;
|
|
|
|
internal_binding->per_stage_offset_in_dwords[stage].secondary =
|
|
reg_usage[stage].secondary_dynamic;
|
|
reg_usage[stage].secondary_dynamic +=
|
|
size_info.secondary * internal_binding->descriptor_count;
|
|
}
|
|
}
|
|
|
|
pvr_setup_in_memory_layout_sizes(layout, reg_usage);
|
|
|
|
#if defined(DEBUG)
|
|
pvr_dump_in_memory_layout_sizes(layout);
|
|
#endif
|
|
|
|
vk_free2(&device->vk.alloc, pAllocator, bindings);
|
|
|
|
*pSetLayout = pvr_descriptor_set_layout_to_handle(layout);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void pvr_DestroyDescriptorSetLayout(VkDevice _device,
|
|
VkDescriptorSetLayout _set_layout,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_descriptor_set_layout, layout, _set_layout);
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
|
|
pvr_descriptor_set_layout_free(device, pAllocator, layout);
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
static void
|
|
pvr_dump_in_register_layout_sizes(const struct pvr_device *device,
|
|
const struct pvr_pipeline_layout *layout)
|
|
{
|
|
mesa_logd("=== SET LAYOUT ===");
|
|
mesa_logd("----------------------------------------------------");
|
|
mesa_logd(" in registers:");
|
|
mesa_logd("----------------------------------------------------");
|
|
|
|
for (uint32_t stage = 0;
|
|
stage < ARRAY_SIZE(layout->register_layout_in_dwords_per_stage);
|
|
stage++) {
|
|
uint32_t dynamic_offset = 0;
|
|
|
|
mesa_logd("| %-48s |", stage_names[stage].primary_dynamic);
|
|
mesa_logd("----------------------------------------------------");
|
|
|
|
/* Print dynamic primaries. */
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
const struct pvr_descriptor_set_layout *const set_layout =
|
|
layout->set_layout[set_num];
|
|
|
|
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&set_layout->bindings[i];
|
|
bool valid = !!(binding->shader_stage_mask & (1U << stage));
|
|
|
|
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
|
|
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
|
|
(valid) ? " " : "X",
|
|
dynamic_offset,
|
|
set_num,
|
|
i,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
|
|
if (valid) {
|
|
struct pvr_descriptor_size_info size_info;
|
|
|
|
pvr_descriptor_size_info_init(device, binding->type, &size_info);
|
|
|
|
dynamic_offset += size_info.primary;
|
|
}
|
|
}
|
|
}
|
|
|
|
mesa_logd("----------------------------------------------------");
|
|
mesa_logd("| %-48s |", stage_names[stage].secondary_dynamic);
|
|
mesa_logd("----------------------------------------------------");
|
|
|
|
/* Print dynamic secondaries. */
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
const struct pvr_descriptor_set_layout *const set_layout =
|
|
layout->set_layout[set_num];
|
|
|
|
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&set_layout->bindings[i];
|
|
bool valid = !!(binding->shader_stage_mask & (1U << stage));
|
|
|
|
if (binding->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC &&
|
|
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
|
|
(valid) ? " " : "X",
|
|
dynamic_offset,
|
|
set_num,
|
|
i,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
|
|
if (valid) {
|
|
struct pvr_descriptor_size_info size_info;
|
|
|
|
pvr_descriptor_size_info_init(device, binding->type, &size_info);
|
|
|
|
dynamic_offset += size_info.secondary;
|
|
}
|
|
}
|
|
}
|
|
|
|
mesa_logd("----------------------------------------------------");
|
|
mesa_logd("| %-48s |", stage_names[stage].primary);
|
|
mesa_logd("----------------------------------------------------");
|
|
|
|
/* Print primaries. */
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
const struct pvr_descriptor_set_layout *const set_layout =
|
|
layout->set_layout[set_num];
|
|
const uint32_t base =
|
|
layout->register_layout_in_dwords_per_stage[stage][set_num]
|
|
.primary_offset;
|
|
|
|
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&set_layout->bindings[i];
|
|
|
|
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
|
|
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
|
|
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
|
|
base + binding->per_stage_offset_in_dwords[stage].primary,
|
|
set_num,
|
|
i,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
}
|
|
}
|
|
|
|
mesa_logd("----------------------------------------------------");
|
|
mesa_logd("| %-48s |", stage_names[stage].secondary);
|
|
mesa_logd("----------------------------------------------------");
|
|
|
|
/* Print secondaries. */
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
const struct pvr_descriptor_set_layout *const set_layout =
|
|
layout->set_layout[set_num];
|
|
const uint32_t base =
|
|
layout->register_layout_in_dwords_per_stage[stage][set_num]
|
|
.secondary_offset;
|
|
|
|
for (uint32_t i = 0; i < set_layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *const binding =
|
|
&set_layout->bindings[i];
|
|
|
|
if (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
|
|
binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
|
|
continue;
|
|
|
|
mesa_logd("| %s %04u | %u:%03u | %-26s[%3u] |",
|
|
(binding->shader_stage_mask & (1U << stage)) ? " " : "X",
|
|
base +
|
|
binding->per_stage_offset_in_dwords[stage].secondary,
|
|
set_num,
|
|
i,
|
|
descriptor_names[binding->type],
|
|
binding->descriptor_count);
|
|
}
|
|
}
|
|
|
|
mesa_logd("====================================================");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Pipeline layouts. These have nothing to do with the pipeline. They are
|
|
* just multiple descriptor set layouts pasted together.
|
|
*/
|
|
VkResult pvr_CreatePipelineLayout(VkDevice _device,
|
|
const VkPipelineLayoutCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkPipelineLayout *pPipelineLayout)
|
|
{
|
|
uint32_t next_free_reg[PVR_STAGE_ALLOCATION_COUNT];
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
struct pvr_pipeline_layout *layout;
|
|
|
|
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO);
|
|
assert(pCreateInfo->setLayoutCount <= PVR_MAX_DESCRIPTOR_SETS);
|
|
|
|
layout = vk_object_alloc(&device->vk,
|
|
pAllocator,
|
|
sizeof(*layout),
|
|
VK_OBJECT_TYPE_PIPELINE_LAYOUT);
|
|
if (!layout)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
layout->set_count = pCreateInfo->setLayoutCount;
|
|
layout->shader_stages = 0;
|
|
for (uint32_t stage = 0; stage < PVR_STAGE_ALLOCATION_COUNT; stage++) {
|
|
uint32_t descriptor_counts
|
|
[PVR_PIPELINE_LAYOUT_SUPPORTED_DESCRIPTOR_TYPE_COUNT] = { 0 };
|
|
struct pvr_pipeline_layout_reg_info *const reg_info =
|
|
&layout->per_stage_reg_info[stage];
|
|
|
|
*reg_info = (struct pvr_pipeline_layout_reg_info){ 0 };
|
|
|
|
layout->per_stage_descriptor_masks[stage] = 0;
|
|
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
/* So we don't write these again and again. Just do it once. */
|
|
if (stage == 0) {
|
|
PVR_FROM_HANDLE(pvr_descriptor_set_layout,
|
|
set_layout,
|
|
pCreateInfo->pSetLayouts[set_num]);
|
|
|
|
layout->set_layout[set_num] = set_layout;
|
|
layout->shader_stages |= set_layout->shader_stages;
|
|
}
|
|
|
|
const struct pvr_descriptor_set_layout_mem_layout *const mem_layout =
|
|
&layout->set_layout[set_num]
|
|
->memory_layout_in_dwords_per_stage[stage];
|
|
|
|
/* Allocate registers counts for dynamic descriptors. */
|
|
reg_info->primary_dynamic_size_in_dwords +=
|
|
mem_layout->primary_dynamic_size;
|
|
reg_info->secondary_dynamic_size_in_dwords +=
|
|
mem_layout->secondary_dynamic_size;
|
|
|
|
for (VkDescriptorType type = 0;
|
|
type < PVR_PIPELINE_LAYOUT_SUPPORTED_DESCRIPTOR_TYPE_COUNT;
|
|
type++) {
|
|
uint32_t descriptor_count;
|
|
|
|
layout->descriptor_offsets[set_num][stage][type] =
|
|
descriptor_counts[type];
|
|
|
|
descriptor_count = layout->set_layout[set_num]
|
|
->per_stage_descriptor_count[stage][type];
|
|
|
|
if (!descriptor_count)
|
|
continue;
|
|
|
|
switch (type) {
|
|
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
|
layout->per_stage_descriptor_masks[stage] |= 1U << set_num;
|
|
descriptor_counts[type] += descriptor_count;
|
|
break;
|
|
|
|
/* We don't need to keep track of the counts or masks for other
|
|
* descriptor types so there is no assert() here since other
|
|
* types are not invalid or unsupported.
|
|
*/
|
|
/* TODO: Improve the comment above to specify why, when we find
|
|
* out.
|
|
*/
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
next_free_reg[stage] = reg_info->primary_dynamic_size_in_dwords +
|
|
reg_info->secondary_dynamic_size_in_dwords;
|
|
}
|
|
|
|
/* Allocate registers counts for primary and secondary descriptors. */
|
|
for (uint32_t stage = 0; stage < PVR_STAGE_ALLOCATION_COUNT; stage++) {
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
const struct pvr_descriptor_set_layout_mem_layout *const mem_layout =
|
|
&layout->set_layout[set_num]
|
|
->memory_layout_in_dwords_per_stage[stage];
|
|
struct pvr_descriptor_set_layout_mem_layout *const reg_layout =
|
|
&layout->register_layout_in_dwords_per_stage[stage][set_num];
|
|
|
|
next_free_reg[stage] = ALIGN_POT(next_free_reg[stage], 4);
|
|
|
|
reg_layout->primary_offset = next_free_reg[stage];
|
|
reg_layout->primary_size = mem_layout->primary_size;
|
|
|
|
next_free_reg[stage] += reg_layout->primary_size;
|
|
}
|
|
|
|
/* To optimize the total shared layout allocation used by the shader,
|
|
* secondary descriptors come last since they're less likely to be used.
|
|
*/
|
|
for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) {
|
|
const struct pvr_descriptor_set_layout_mem_layout *const mem_layout =
|
|
&layout->set_layout[set_num]
|
|
->memory_layout_in_dwords_per_stage[stage];
|
|
struct pvr_descriptor_set_layout_mem_layout *const reg_layout =
|
|
&layout->register_layout_in_dwords_per_stage[stage][set_num];
|
|
|
|
/* Should we be aligning next_free_reg like it's done with the
|
|
* primary descriptors?
|
|
*/
|
|
|
|
reg_layout->secondary_offset = next_free_reg[stage];
|
|
reg_layout->secondary_size = mem_layout->secondary_size;
|
|
|
|
next_free_reg[stage] += reg_layout->secondary_size;
|
|
}
|
|
}
|
|
|
|
layout->push_constants_shader_stages = 0;
|
|
for (uint32_t i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
|
|
const VkPushConstantRange *range = &pCreateInfo->pPushConstantRanges[i];
|
|
|
|
layout->push_constants_shader_stages |= range->stageFlags;
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
pvr_dump_in_register_layout_sizes(device, layout);
|
|
#endif
|
|
|
|
*pPipelineLayout = pvr_pipeline_layout_to_handle(layout);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void pvr_DestroyPipelineLayout(VkDevice _device,
|
|
VkPipelineLayout _pipelineLayout,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
PVR_FROM_HANDLE(pvr_pipeline_layout, layout, _pipelineLayout);
|
|
|
|
vk_object_free(&device->vk, pAllocator, layout);
|
|
}
|
|
|
|
VkResult pvr_CreateDescriptorPool(VkDevice _device,
|
|
const VkDescriptorPoolCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkDescriptorPool *pDescriptorPool)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
struct pvr_descriptor_pool *pool;
|
|
|
|
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO);
|
|
|
|
pool = vk_object_alloc(&device->vk,
|
|
pAllocator,
|
|
sizeof(*pool),
|
|
VK_OBJECT_TYPE_DESCRIPTOR_POOL);
|
|
if (!pool)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
if (pAllocator)
|
|
pool->alloc = *pAllocator;
|
|
else
|
|
pool->alloc = device->vk.alloc;
|
|
|
|
pool->max_sets = pCreateInfo->maxSets;
|
|
list_inithead(&pool->descriptor_sets);
|
|
|
|
pool->total_size_in_dwords = 0;
|
|
for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++) {
|
|
struct pvr_descriptor_size_info size_info;
|
|
const uint32_t descriptor_count =
|
|
pCreateInfo->pPoolSizes[i].descriptorCount;
|
|
|
|
pvr_descriptor_size_info_init(device,
|
|
pCreateInfo->pPoolSizes[i].type,
|
|
&size_info);
|
|
|
|
const uint32_t secondary = ALIGN_POT(size_info.secondary, 4);
|
|
const uint32_t primary = ALIGN_POT(size_info.primary, 4);
|
|
|
|
pool->total_size_in_dwords += descriptor_count * (primary + secondary);
|
|
}
|
|
pool->total_size_in_dwords *= PVR_STAGE_ALLOCATION_COUNT;
|
|
pool->current_size_in_dwords = 0;
|
|
|
|
pvr_finishme("Entry tracker for allocations?");
|
|
|
|
*pDescriptorPool = pvr_descriptor_pool_to_handle(pool);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static void pvr_free_descriptor_set(struct pvr_device *device,
|
|
struct pvr_descriptor_pool *pool,
|
|
struct pvr_descriptor_set *set)
|
|
{
|
|
list_del(&set->link);
|
|
pvr_bo_free(device, set->pvr_bo);
|
|
vk_object_free(&device->vk, &pool->alloc, set);
|
|
}
|
|
|
|
void pvr_DestroyDescriptorPool(VkDevice _device,
|
|
VkDescriptorPool _pool,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
PVR_FROM_HANDLE(pvr_descriptor_pool, pool, _pool);
|
|
|
|
if (!pool)
|
|
return;
|
|
|
|
list_for_each_entry_safe (struct pvr_descriptor_set,
|
|
set,
|
|
&pool->descriptor_sets,
|
|
link) {
|
|
pvr_free_descriptor_set(device, pool, set);
|
|
}
|
|
|
|
vk_object_free(&device->vk, pAllocator, pool);
|
|
}
|
|
|
|
VkResult pvr_ResetDescriptorPool(VkDevice _device,
|
|
VkDescriptorPool descriptorPool,
|
|
VkDescriptorPoolResetFlags flags)
|
|
{
|
|
assert(!"Unimplemented");
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static uint16_t pvr_get_descriptor_primary_offset(
|
|
const struct pvr_device *device,
|
|
const struct pvr_descriptor_set_layout *layout,
|
|
const struct pvr_descriptor_set_layout_binding *binding,
|
|
const uint32_t stage,
|
|
const uint32_t desc_idx)
|
|
{
|
|
struct pvr_descriptor_size_info size_info;
|
|
uint32_t offset;
|
|
|
|
assert(stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage));
|
|
assert(desc_idx < binding->descriptor_count);
|
|
|
|
pvr_descriptor_size_info_init(device, binding->type, &size_info);
|
|
|
|
offset = layout->memory_layout_in_dwords_per_stage[stage].primary_offset;
|
|
offset += binding->per_stage_offset_in_dwords[stage].primary;
|
|
offset += (desc_idx * size_info.primary);
|
|
|
|
/* Offset must be less than 16bits. */
|
|
assert(offset < UINT16_MAX);
|
|
|
|
return (uint16_t)offset;
|
|
}
|
|
|
|
static uint16_t pvr_get_descriptor_secondary_offset(
|
|
const struct pvr_device *device,
|
|
const struct pvr_descriptor_set_layout *layout,
|
|
const struct pvr_descriptor_set_layout_binding *binding,
|
|
const uint32_t stage,
|
|
const uint32_t desc_idx)
|
|
{
|
|
struct pvr_descriptor_size_info size_info;
|
|
uint32_t offset;
|
|
|
|
assert(stage < ARRAY_SIZE(layout->memory_layout_in_dwords_per_stage));
|
|
assert(desc_idx < binding->descriptor_count);
|
|
|
|
pvr_descriptor_size_info_init(device, binding->type, &size_info);
|
|
|
|
offset = layout->memory_layout_in_dwords_per_stage[stage].secondary_offset;
|
|
offset += binding->per_stage_offset_in_dwords[stage].secondary;
|
|
offset += (desc_idx * size_info.secondary);
|
|
|
|
/* Offset must be less than 16bits. */
|
|
assert(offset < UINT16_MAX);
|
|
|
|
return (uint16_t)offset;
|
|
}
|
|
|
|
#define PVR_MAX_DESCRIPTOR_MEM_SIZE_IN_DWORDS (4 * 1024)
|
|
|
|
static VkResult
|
|
pvr_descriptor_set_create(struct pvr_device *device,
|
|
struct pvr_descriptor_pool *pool,
|
|
const struct pvr_descriptor_set_layout *layout,
|
|
struct pvr_descriptor_set **const descriptor_set_out)
|
|
{
|
|
struct pvr_descriptor_set *set;
|
|
VkResult result;
|
|
size_t size;
|
|
void *map;
|
|
|
|
size = sizeof(*set) + sizeof(set->descriptors[0]) * layout->descriptor_count;
|
|
|
|
/* TODO: Add support to allocate descriptors from descriptor pool, also
|
|
* check the required descriptors must not exceed max allowed descriptors.
|
|
*/
|
|
set = vk_object_zalloc(&device->vk,
|
|
&pool->alloc,
|
|
size,
|
|
VK_OBJECT_TYPE_DESCRIPTOR_SET);
|
|
if (!set)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
/* TODO: Add support to allocate device memory from a common pool. Look at
|
|
* something like anv. Also we can allocate a whole chunk of device memory
|
|
* for max descriptors supported by pool as done by v3dv. Also check the
|
|
* possibility if this can be removed from here and done on need basis.
|
|
*/
|
|
|
|
if (layout->binding_count > 0) {
|
|
const uint32_t cache_line_size =
|
|
rogue_get_slc_cache_line_size(&device->pdevice->dev_info);
|
|
uint64_t bo_size = MIN2(pool->total_size_in_dwords,
|
|
PVR_MAX_DESCRIPTOR_MEM_SIZE_IN_DWORDS) *
|
|
sizeof(uint32_t);
|
|
|
|
result = pvr_bo_alloc(device,
|
|
device->heaps.general_heap,
|
|
bo_size,
|
|
cache_line_size,
|
|
PVR_BO_ALLOC_FLAG_CPU_MAPPED,
|
|
&set->pvr_bo);
|
|
if (result != VK_SUCCESS)
|
|
goto err_free_descriptor_set;
|
|
}
|
|
|
|
set->layout = layout;
|
|
set->pool = pool;
|
|
|
|
map = set->pvr_bo->bo->map;
|
|
for (uint32_t i = 0; i < layout->binding_count; i++) {
|
|
const struct pvr_descriptor_set_layout_binding *binding =
|
|
&layout->bindings[i];
|
|
|
|
if (binding->descriptor_count == 0 || !binding->has_immutable_samplers)
|
|
continue;
|
|
|
|
for (uint32_t stage = 0;
|
|
stage < ARRAY_SIZE(binding->per_stage_offset_in_dwords);
|
|
stage++) {
|
|
if (!(binding->shader_stage_mask & (1U << stage)))
|
|
continue;
|
|
|
|
for (uint32_t j = 0; j < binding->descriptor_count; j++) {
|
|
uint32_t idx = binding->immutable_samplers_index + j;
|
|
const struct pvr_sampler *sampler = layout->immutable_samplers[idx];
|
|
unsigned int offset_in_dwords =
|
|
pvr_get_descriptor_primary_offset(device,
|
|
layout,
|
|
binding,
|
|
stage,
|
|
j);
|
|
|
|
if (binding->type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
|
|
offset_in_dwords += 4;
|
|
|
|
memcpy((uint8_t *)map + offset_in_dwords * sizeof(uint32_t),
|
|
sampler->descriptor.words,
|
|
sizeof(sampler->descriptor.words));
|
|
}
|
|
}
|
|
}
|
|
|
|
list_addtail(&set->link, &pool->descriptor_sets);
|
|
|
|
*descriptor_set_out = set;
|
|
|
|
return VK_SUCCESS;
|
|
|
|
err_free_descriptor_set:
|
|
vk_object_free(&device->vk, &pool->alloc, set);
|
|
|
|
return result;
|
|
}
|
|
|
|
VkResult
|
|
pvr_AllocateDescriptorSets(VkDevice _device,
|
|
const VkDescriptorSetAllocateInfo *pAllocateInfo,
|
|
VkDescriptorSet *pDescriptorSets)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_descriptor_pool, pool, pAllocateInfo->descriptorPool);
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
VkResult result;
|
|
uint32_t i;
|
|
|
|
vk_foreach_struct_const (ext, pAllocateInfo->pNext) {
|
|
pvr_debug_ignored_stype(ext->sType);
|
|
}
|
|
|
|
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
|
|
PVR_FROM_HANDLE(pvr_descriptor_set_layout,
|
|
layout,
|
|
pAllocateInfo->pSetLayouts[i]);
|
|
struct pvr_descriptor_set *set = NULL;
|
|
|
|
result = pvr_descriptor_set_create(device, pool, layout, &set);
|
|
if (result != VK_SUCCESS)
|
|
goto err_free_descriptor_sets;
|
|
|
|
pDescriptorSets[i] = pvr_descriptor_set_to_handle(set);
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
|
|
err_free_descriptor_sets:
|
|
pvr_FreeDescriptorSets(_device,
|
|
pAllocateInfo->descriptorPool,
|
|
i,
|
|
pDescriptorSets);
|
|
|
|
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++)
|
|
pDescriptorSets[i] = VK_NULL_HANDLE;
|
|
|
|
return result;
|
|
}
|
|
|
|
VkResult pvr_FreeDescriptorSets(VkDevice _device,
|
|
VkDescriptorPool descriptorPool,
|
|
uint32_t count,
|
|
const VkDescriptorSet *pDescriptorSets)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_descriptor_pool, pool, descriptorPool);
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
struct pvr_descriptor_set *set;
|
|
|
|
if (!pDescriptorSets[i])
|
|
continue;
|
|
|
|
set = pvr_descriptor_set_from_handle(pDescriptorSets[i]);
|
|
pvr_free_descriptor_set(device, pool, set);
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static int pvr_compare_layout_binding(const void *a, const void *b)
|
|
{
|
|
uint32_t binding_a;
|
|
uint32_t binding_b;
|
|
|
|
binding_a = ((struct pvr_descriptor_set_layout_binding *)a)->binding_number;
|
|
binding_b = ((struct pvr_descriptor_set_layout_binding *)b)->binding_number;
|
|
|
|
if (binding_a < binding_b)
|
|
return -1;
|
|
|
|
if (binding_a > binding_b)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* This function does not assume that the binding will always exist for a
|
|
* particular binding_num. Caller should check before using the return pointer.
|
|
*/
|
|
static struct pvr_descriptor_set_layout_binding *
|
|
pvr_get_descriptor_binding(const struct pvr_descriptor_set_layout *layout,
|
|
const uint32_t binding_num)
|
|
{
|
|
struct pvr_descriptor_set_layout_binding binding;
|
|
binding.binding_number = binding_num;
|
|
|
|
return bsearch(&binding,
|
|
layout->bindings,
|
|
layout->binding_count,
|
|
sizeof(binding),
|
|
pvr_compare_layout_binding);
|
|
}
|
|
|
|
static void pvr_descriptor_update_buffer_info(
|
|
const struct pvr_device *device,
|
|
const VkWriteDescriptorSet *write_set,
|
|
struct pvr_descriptor_set *set,
|
|
const struct pvr_descriptor_set_layout_binding *binding,
|
|
uint32_t *mem_ptr,
|
|
uint32_t start_stage,
|
|
uint32_t end_stage)
|
|
{
|
|
struct pvr_descriptor_size_info size_info;
|
|
bool is_dynamic;
|
|
|
|
is_dynamic = (binding->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
|
|
(binding->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
|
|
|
|
pvr_descriptor_size_info_init(device, binding->type, &size_info);
|
|
|
|
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
|
|
const VkDescriptorBufferInfo *buffer_info = &write_set->pBufferInfo[i];
|
|
PVR_FROM_HANDLE(pvr_buffer, buffer, buffer_info->buffer);
|
|
const uint32_t desc_idx =
|
|
binding->descriptor_index + write_set->dstArrayElement + i;
|
|
const pvr_dev_addr_t addr =
|
|
PVR_DEV_ADDR_OFFSET(buffer->dev_addr, buffer_info->offset);
|
|
uint32_t range = (buffer_info->range == VK_WHOLE_SIZE)
|
|
? (buffer->vk.size - buffer_info->offset)
|
|
: (buffer_info->range);
|
|
|
|
set->descriptors[desc_idx].type = write_set->descriptorType;
|
|
set->descriptors[desc_idx].buffer_dev_addr = addr;
|
|
set->descriptors[desc_idx].buffer_create_info_size = buffer->vk.size;
|
|
set->descriptors[desc_idx].buffer_desc_range = range;
|
|
|
|
if (is_dynamic)
|
|
continue;
|
|
|
|
/* Update the entries in the descriptor memory for static buffer. */
|
|
for (uint32_t j = start_stage; j < end_stage; j++) {
|
|
uint32_t primary_offset;
|
|
uint32_t secondary_offset;
|
|
|
|
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
|
|
continue;
|
|
|
|
/* Offset calculation functions expect descriptor_index to be
|
|
* binding relative not layout relative, so we have used
|
|
* write_set->dstArrayElement + i rather than desc_idx.
|
|
*/
|
|
primary_offset =
|
|
pvr_get_descriptor_primary_offset(device,
|
|
set->layout,
|
|
binding,
|
|
j,
|
|
write_set->dstArrayElement + i);
|
|
secondary_offset =
|
|
pvr_get_descriptor_secondary_offset(device,
|
|
set->layout,
|
|
binding,
|
|
j,
|
|
write_set->dstArrayElement + i);
|
|
|
|
memcpy(mem_ptr + primary_offset, &addr, size_info.primary << 2);
|
|
memcpy(mem_ptr + secondary_offset, &range, size_info.secondary << 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pvr_descriptor_update_sampler(
|
|
const struct pvr_device *device,
|
|
const VkWriteDescriptorSet *write_set,
|
|
struct pvr_descriptor_set *set,
|
|
const struct pvr_descriptor_set_layout_binding *binding,
|
|
uint32_t *mem_ptr,
|
|
uint32_t start_stage,
|
|
uint32_t end_stage)
|
|
{
|
|
struct pvr_descriptor_size_info size_info;
|
|
|
|
pvr_descriptor_size_info_init(device, binding->type, &size_info);
|
|
|
|
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
|
|
PVR_FROM_HANDLE(pvr_sampler, sampler, write_set->pImageInfo[i].sampler);
|
|
const uint32_t desc_idx =
|
|
binding->descriptor_index + write_set->dstArrayElement + i;
|
|
|
|
set->descriptors[desc_idx].type = write_set->descriptorType;
|
|
set->descriptors[desc_idx].sampler = sampler;
|
|
|
|
for (uint32_t j = start_stage; j < end_stage; j++) {
|
|
uint32_t primary_offset;
|
|
|
|
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
|
|
continue;
|
|
|
|
/* Offset calculation functions expect descriptor_index to be binding
|
|
* relative not layout relative, so we have used
|
|
* write_set->dstArrayElement + i rather than desc_idx.
|
|
*/
|
|
primary_offset =
|
|
pvr_get_descriptor_primary_offset(device,
|
|
set->layout,
|
|
binding,
|
|
j,
|
|
write_set->dstArrayElement + i);
|
|
|
|
memcpy(mem_ptr + primary_offset,
|
|
sampler->descriptor.words,
|
|
sizeof(sampler->descriptor.words));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
pvr_write_image_descriptor_primaries(const struct pvr_device_info *dev_info,
|
|
const struct pvr_image_view *iview,
|
|
VkDescriptorType descriptorType,
|
|
uint32_t *primary)
|
|
{
|
|
uint64_t *qword_ptr = (uint64_t *)primary;
|
|
|
|
if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
|
|
(iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE ||
|
|
iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)) {
|
|
qword_ptr[0] = iview->texture_state[PVR_TEXTURE_STATE_STORAGE][0];
|
|
qword_ptr[1] = iview->texture_state[PVR_TEXTURE_STATE_STORAGE][1];
|
|
} else if (descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) {
|
|
qword_ptr[0] = iview->texture_state[PVR_TEXTURE_STATE_ATTACHMENT][0];
|
|
qword_ptr[1] = iview->texture_state[PVR_TEXTURE_STATE_ATTACHMENT][1];
|
|
} else {
|
|
qword_ptr[0] = iview->texture_state[PVR_TEXTURE_STATE_SAMPLE][0];
|
|
qword_ptr[1] = iview->texture_state[PVR_TEXTURE_STATE_SAMPLE][1];
|
|
}
|
|
|
|
if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
|
|
!PVR_HAS_FEATURE(dev_info, tpu_extended_integer_lookup)) {
|
|
uint64_t tmp;
|
|
|
|
pvr_csb_pack (&tmp, TEXSTATE_STRIDE_IMAGE_WORD1, word1) {
|
|
word1.index_lookup = true;
|
|
}
|
|
|
|
qword_ptr[1] |= tmp;
|
|
}
|
|
}
|
|
|
|
static void
|
|
pvr_write_image_descriptor_secondaries(const struct pvr_device_info *dev_info,
|
|
const struct pvr_image_view *iview,
|
|
VkDescriptorType descriptorType,
|
|
uint32_t *secondary)
|
|
{
|
|
const bool cube_array_adjust =
|
|
descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
|
|
iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
|
|
|
if (!PVR_HAS_FEATURE(dev_info, tpu_array_textures)) {
|
|
uint64_t addr = iview->image->dev_addr.addr +
|
|
iview->vk.base_array_layer * iview->image->layer_size;
|
|
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE] = (uint32_t)addr;
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYBASE + 1U] =
|
|
(uint32_t)(addr >> 32U);
|
|
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYSTRIDE] =
|
|
cube_array_adjust ? iview->image->layer_size * 6
|
|
: iview->image->layer_size;
|
|
}
|
|
|
|
if (cube_array_adjust) {
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info)] =
|
|
iview->vk.layer_count / 6 - 1;
|
|
} else {
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_ARRAYMAXINDEX(dev_info)] =
|
|
iview->vk.layer_count - 1;
|
|
}
|
|
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_WIDTH(dev_info)] =
|
|
iview->vk.extent.width;
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_HEIGHT(dev_info)] =
|
|
iview->vk.extent.height;
|
|
secondary[PVR_DESC_IMAGE_SECONDARY_OFFSET_DEPTH(dev_info)] =
|
|
iview->vk.extent.depth;
|
|
}
|
|
|
|
static void pvr_descriptor_update_sampler_texture(
|
|
const struct pvr_device *device,
|
|
const VkWriteDescriptorSet *write_set,
|
|
struct pvr_descriptor_set *set,
|
|
const struct pvr_descriptor_set_layout_binding *binding,
|
|
uint32_t *mem_ptr,
|
|
uint32_t start_stage,
|
|
uint32_t end_stage)
|
|
{
|
|
const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
|
|
|
|
for (uint32_t i = 0; i < write_set->descriptorCount; i++) {
|
|
PVR_FROM_HANDLE(pvr_image_view,
|
|
iview,
|
|
write_set->pImageInfo[i].imageView);
|
|
const uint32_t desc_idx =
|
|
binding->descriptor_index + write_set->dstArrayElement + i;
|
|
|
|
set->descriptors[desc_idx].type = write_set->descriptorType;
|
|
set->descriptors[desc_idx].iview = iview;
|
|
set->descriptors[desc_idx].layout = write_set->pImageInfo[i].imageLayout;
|
|
|
|
for (uint32_t j = start_stage; j < end_stage; j++) {
|
|
uint32_t secondary_offset;
|
|
uint32_t primary_offset;
|
|
|
|
if (!(binding->shader_stage_mask & BITFIELD_BIT(j)))
|
|
continue;
|
|
|
|
/* Offset calculation functions expect descriptor_index to be
|
|
* binding relative not layout relative, so we have used
|
|
* write_set->dstArrayElement + i rather than desc_idx.
|
|
*/
|
|
primary_offset =
|
|
pvr_get_descriptor_primary_offset(device,
|
|
set->layout,
|
|
binding,
|
|
j,
|
|
write_set->dstArrayElement + i);
|
|
secondary_offset =
|
|
pvr_get_descriptor_secondary_offset(device,
|
|
set->layout,
|
|
binding,
|
|
j,
|
|
write_set->dstArrayElement + i);
|
|
|
|
pvr_write_image_descriptor_primaries(dev_info,
|
|
iview,
|
|
write_set->descriptorType,
|
|
mem_ptr + primary_offset);
|
|
|
|
/* We don't need to update the sampler words if they belong to an
|
|
* immutable sampler.
|
|
*/
|
|
if (!binding->has_immutable_samplers) {
|
|
PVR_FROM_HANDLE(pvr_sampler,
|
|
sampler,
|
|
write_set->pImageInfo[i].sampler);
|
|
set->descriptors[desc_idx].sampler = sampler;
|
|
|
|
/* Sampler words are located at the end of the primary image words.
|
|
*/
|
|
memcpy(mem_ptr + primary_offset + PVR_IMAGE_DESCRIPTOR_SIZE,
|
|
sampler->descriptor.words,
|
|
sizeof(sampler->descriptor.words));
|
|
}
|
|
|
|
pvr_write_image_descriptor_secondaries(dev_info,
|
|
iview,
|
|
write_set->descriptorType,
|
|
mem_ptr + secondary_offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pvr_UpdateDescriptorSets(VkDevice _device,
|
|
uint32_t descriptorWriteCount,
|
|
const VkWriteDescriptorSet *pDescriptorWrites,
|
|
uint32_t descriptorCopyCount,
|
|
const VkCopyDescriptorSet *pDescriptorCopies)
|
|
{
|
|
PVR_FROM_HANDLE(pvr_device, device, _device);
|
|
|
|
for (uint32_t i = 0; i < descriptorWriteCount; i++) {
|
|
const VkWriteDescriptorSet *write_set = &pDescriptorWrites[i];
|
|
PVR_FROM_HANDLE(pvr_descriptor_set, set, write_set->dstSet);
|
|
uint32_t *map = set->pvr_bo->bo->map;
|
|
const struct pvr_descriptor_set_layout_binding *binding =
|
|
pvr_get_descriptor_binding(set->layout, write_set->dstBinding);
|
|
|
|
/* Binding should not be NULL. */
|
|
assert(binding);
|
|
|
|
/* Only need to update the descriptor if it is actually being used. If it
|
|
* was not used in any stage, then the shader_stage_mask would be 0 and we
|
|
* can skip this update.
|
|
*/
|
|
if (binding->shader_stage_mask == 0)
|
|
continue;
|
|
|
|
vk_foreach_struct_const (ext, write_set->pNext) {
|
|
pvr_debug_ignored_stype(ext->sType);
|
|
}
|
|
|
|
switch (write_set->descriptorType) {
|
|
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
|
pvr_descriptor_update_sampler(device,
|
|
write_set,
|
|
set,
|
|
binding,
|
|
map,
|
|
0,
|
|
PVR_STAGE_ALLOCATION_COUNT);
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
|
pvr_descriptor_update_sampler_texture(device,
|
|
write_set,
|
|
set,
|
|
binding,
|
|
map,
|
|
0,
|
|
PVR_STAGE_ALLOCATION_COUNT);
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
|
pvr_finishme("Update support missing for %d descriptor type\n",
|
|
write_set->descriptorType);
|
|
break;
|
|
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
|
pvr_descriptor_update_buffer_info(device,
|
|
write_set,
|
|
set,
|
|
binding,
|
|
map,
|
|
0,
|
|
PVR_STAGE_ALLOCATION_COUNT);
|
|
break;
|
|
|
|
default:
|
|
unreachable("Unknown descriptor type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (descriptorCopyCount > 0)
|
|
pvr_finishme("Descriptor copying support missing\n");
|
|
}
|