mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-19 22:18:18 +02:00
ail is a more sensible place for the format tables to live. this does create a bit of dependency soup but hey. nfc Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30981>
195 lines
6.5 KiB
C
195 lines
6.5 KiB
C
/*
|
|
* Copyright 2024 Valve Corporation
|
|
* Copyright 2024 Alyssa Rosenzweig
|
|
* Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
#include "hk_buffer_view.h"
|
|
#include "asahi/layout/layout.h"
|
|
#include "asahi/lib/agx_nir_lower_vbo.h"
|
|
#include "util/bitscan.h"
|
|
#include "util/format/u_format.h"
|
|
#include "util/format/u_formats.h"
|
|
|
|
#include "agx_helpers.h"
|
|
#include "agx_nir_passes.h"
|
|
#include "agx_pack.h"
|
|
#include "hk_buffer.h"
|
|
#include "hk_device.h"
|
|
#include "hk_entrypoints.h"
|
|
#include "hk_physical_device.h"
|
|
|
|
#include "vk_format.h"
|
|
|
|
VkFormatFeatureFlags2
|
|
hk_get_buffer_format_features(struct hk_physical_device *pdev,
|
|
VkFormat vk_format)
|
|
{
|
|
VkFormatFeatureFlags2 features = 0;
|
|
enum pipe_format p_format = vk_format_to_pipe_format(vk_format);
|
|
|
|
if (p_format == PIPE_FORMAT_NONE)
|
|
return 0;
|
|
|
|
if (agx_vbo_supports_format(p_format))
|
|
features |= VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT;
|
|
|
|
if (ail_pixel_format[p_format].texturable &&
|
|
!util_format_is_depth_or_stencil(p_format)) {
|
|
|
|
features |= VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT;
|
|
|
|
/* RGB32 specially supported for uniform texel buffers only. */
|
|
if (util_is_power_of_two_nonzero(util_format_get_blocksize(p_format))) {
|
|
features |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT |
|
|
VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
|
|
}
|
|
|
|
if (p_format == PIPE_FORMAT_R32_UINT || p_format == PIPE_FORMAT_R32_SINT)
|
|
features |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
|
|
}
|
|
|
|
return features;
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL
|
|
hk_CreateBufferView(VkDevice _device, const VkBufferViewCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkBufferView *pBufferView)
|
|
{
|
|
VK_FROM_HANDLE(hk_device, device, _device);
|
|
VK_FROM_HANDLE(hk_buffer, buffer, pCreateInfo->buffer);
|
|
struct hk_buffer_view *view;
|
|
VkResult result;
|
|
|
|
view = vk_buffer_view_create(&device->vk, pCreateInfo, pAllocator,
|
|
sizeof(*view));
|
|
if (!view)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
enum pipe_format format = vk_format_to_pipe_format(view->vk.format);
|
|
const struct util_format_description *desc = util_format_description(format);
|
|
|
|
uint8_t format_swizzle[4] = {
|
|
desc->swizzle[0],
|
|
desc->swizzle[1],
|
|
desc->swizzle[2],
|
|
desc->swizzle[3],
|
|
};
|
|
|
|
if (util_format_is_depth_or_stencil(format)) {
|
|
assert(!util_format_is_depth_and_stencil(format) &&
|
|
"separate stencil always used");
|
|
|
|
/* Broadcast depth and stencil */
|
|
format_swizzle[0] = 0;
|
|
format_swizzle[1] = 0;
|
|
format_swizzle[2] = 0;
|
|
format_swizzle[3] = 0;
|
|
}
|
|
|
|
/* Decompose the offset into a multiple of 16-bytes (which we can include in
|
|
* the address) and an extra texel-aligned tail offset of up to 15 bytes.
|
|
*
|
|
* This lets us offset partially in the shader instead, getting
|
|
* around alignment restrictions on the base address pointer.
|
|
*/
|
|
uint64_t base = hk_buffer_address(buffer, 0) + (view->vk.offset & ~0xf);
|
|
uint32_t tail_offset_B = view->vk.offset & 0xf;
|
|
uint32_t tail_offset_el = tail_offset_B / util_format_get_blocksize(format);
|
|
assert(tail_offset_el * util_format_get_blocksize(format) == tail_offset_B &&
|
|
"must be texel aligned");
|
|
|
|
struct agx_texture_packed tex;
|
|
agx_pack(&tex, TEXTURE, cfg) {
|
|
cfg.dimension = AGX_TEXTURE_DIMENSION_2D;
|
|
cfg.layout = AGX_LAYOUT_LINEAR;
|
|
cfg.channels = ail_pixel_format[format].channels;
|
|
cfg.type = ail_pixel_format[format].type;
|
|
cfg.swizzle_r = agx_channel_from_pipe(format_swizzle[0]);
|
|
cfg.swizzle_g = agx_channel_from_pipe(format_swizzle[1]);
|
|
cfg.swizzle_b = agx_channel_from_pipe(format_swizzle[2]);
|
|
cfg.swizzle_a = agx_channel_from_pipe(format_swizzle[3]);
|
|
|
|
cfg.width = AGX_TEXTURE_BUFFER_WIDTH;
|
|
cfg.height = DIV_ROUND_UP(view->vk.elements, cfg.width);
|
|
cfg.first_level = cfg.last_level = 0;
|
|
|
|
cfg.address = base;
|
|
cfg.buffer_size_sw = view->vk.elements;
|
|
cfg.buffer_offset_sw = tail_offset_el;
|
|
|
|
cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
|
|
cfg.srgb_2_channel = cfg.srgb && util_format_colormask(desc) == 0x3;
|
|
|
|
cfg.depth = 1;
|
|
cfg.stride = (cfg.width * util_format_get_blocksize(format)) - 16;
|
|
}
|
|
|
|
struct agx_pbe_packed pbe;
|
|
agx_pack(&pbe, PBE, cfg) {
|
|
cfg.dimension = AGX_TEXTURE_DIMENSION_2D;
|
|
cfg.layout = AGX_LAYOUT_LINEAR;
|
|
cfg.channels = ail_pixel_format[format].channels;
|
|
cfg.type = ail_pixel_format[format].type;
|
|
cfg.srgb = util_format_is_srgb(format);
|
|
|
|
assert(desc->nr_channels >= 1 && desc->nr_channels <= 4);
|
|
|
|
for (unsigned i = 0; i < desc->nr_channels; ++i) {
|
|
if (desc->swizzle[i] == 0)
|
|
cfg.swizzle_r = i;
|
|
else if (desc->swizzle[i] == 1)
|
|
cfg.swizzle_g = i;
|
|
else if (desc->swizzle[i] == 2)
|
|
cfg.swizzle_b = i;
|
|
else if (desc->swizzle[i] == 3)
|
|
cfg.swizzle_a = i;
|
|
}
|
|
|
|
cfg.buffer = base;
|
|
cfg.buffer_offset_sw = tail_offset_el;
|
|
|
|
cfg.width = AGX_TEXTURE_BUFFER_WIDTH;
|
|
cfg.height = DIV_ROUND_UP(view->vk.elements, cfg.width);
|
|
cfg.level = 0;
|
|
cfg.stride = (cfg.width * util_format_get_blocksize(format)) - 4;
|
|
cfg.layers = 1;
|
|
cfg.levels = 1;
|
|
};
|
|
|
|
result = hk_descriptor_table_add(device, &device->images, &tex, sizeof(tex),
|
|
&view->tex_desc_index);
|
|
if (result != VK_SUCCESS) {
|
|
vk_buffer_view_destroy(&device->vk, pAllocator, &view->vk);
|
|
return result;
|
|
}
|
|
|
|
result = hk_descriptor_table_add(device, &device->images, &pbe, sizeof(pbe),
|
|
&view->pbe_desc_index);
|
|
if (result != VK_SUCCESS) {
|
|
hk_descriptor_table_remove(device, &device->images, view->tex_desc_index);
|
|
vk_buffer_view_destroy(&device->vk, pAllocator, &view->vk);
|
|
return result;
|
|
}
|
|
|
|
*pBufferView = hk_buffer_view_to_handle(view);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
hk_DestroyBufferView(VkDevice _device, VkBufferView bufferView,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
VK_FROM_HANDLE(hk_device, device, _device);
|
|
VK_FROM_HANDLE(hk_buffer_view, view, bufferView);
|
|
|
|
if (!view)
|
|
return;
|
|
|
|
hk_descriptor_table_remove(device, &device->images, view->tex_desc_index);
|
|
hk_descriptor_table_remove(device, &device->images, view->pbe_desc_index);
|
|
|
|
vk_buffer_view_destroy(&device->vk, pAllocator, &view->vk);
|
|
}
|