blob: cc2874823e94778164c50ae1c62ab059647fdcb6 [file] [log] [blame]
/*
* Copyright © 2021 Collabora 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 "nir/nir_builder.h"
#include "pan_blitter.h"
#include "pan_encoder.h"
#include "pan_shader.h"
#include "panvk_private.h"
#include "panvk_vX_meta.h"
#include "vk_format.h"
static mali_ptr
panvk_meta_clear_color_attachment_shader(struct panfrost_device *pdev,
struct pan_pool *bin_pool,
enum glsl_base_type base_type,
struct pan_shader_info *shader_info)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
GENX(pan_shader_get_compiler_options)(),
"panvk_meta_clear_attachment(base_type=%d)",
base_type);
const struct glsl_type *out_type = glsl_vector_type(base_type, 4);
nir_variable *out =
nir_variable_create(b.shader, nir_var_shader_out, out_type, "out");
out->data.location = FRAG_RESULT_DATA0;
nir_ssa_def *clear_values = nir_load_push_constant(&b, 4, 32,
nir_imm_int(&b, 0),
.range = ~0);
nir_store_var(&b, out, clear_values, 0xff);
struct panfrost_compile_inputs inputs = {
.gpu_id = pdev->gpu_id,
.is_blit = true,
.no_ubo_to_push = true,
};
struct util_dynarray binary;
util_dynarray_init(&binary, NULL);
GENX(pan_shader_compile)(b.shader, &inputs, &binary, shader_info);
shader_info->push.count = 4;
mali_ptr shader =
pan_pool_upload_aligned(bin_pool, binary.data, binary.size, 128);
util_dynarray_fini(&binary);
ralloc_free(b.shader);
return shader;
}
static mali_ptr
panvk_meta_clear_color_attachment_emit_rsd(struct panfrost_device *pdev,
struct pan_pool *desc_pool,
enum pipe_format format,
unsigned rt,
struct pan_shader_info *shader_info,
mali_ptr shader)
{
struct panfrost_ptr rsd_ptr =
pan_pool_alloc_desc_aggregate(desc_pool,
PAN_DESC(RENDERER_STATE),
PAN_DESC_ARRAY(rt + 1, BLEND));
pan_pack(rsd_ptr.cpu, RENDERER_STATE, cfg) {
pan_shader_prepare_rsd(shader_info, shader, &cfg);
cfg.properties.depth_source = MALI_DEPTH_SOURCE_FIXED_FUNCTION;
cfg.multisample_misc.sample_mask = UINT16_MAX;
cfg.multisample_misc.depth_function = MALI_FUNC_ALWAYS;
cfg.properties.allow_forward_pixel_to_be_killed = true;
cfg.properties.allow_forward_pixel_to_kill = true;
cfg.properties.zs_update_operation = MALI_PIXEL_KILL_WEAK_EARLY;
cfg.properties.pixel_kill_operation = MALI_PIXEL_KILL_WEAK_EARLY;
}
void *bd = rsd_ptr.cpu + pan_size(RENDERER_STATE);
pan_pack(bd, BLEND, cfg) {
cfg.round_to_fb_precision = true;
cfg.load_destination = false;
cfg.equation.rgb.a = MALI_BLEND_OPERAND_A_SRC;
cfg.equation.rgb.b = MALI_BLEND_OPERAND_B_SRC;
cfg.equation.rgb.c = MALI_BLEND_OPERAND_C_ZERO;
cfg.equation.alpha.a = MALI_BLEND_OPERAND_A_SRC;
cfg.equation.alpha.b = MALI_BLEND_OPERAND_B_SRC;
cfg.equation.alpha.c = MALI_BLEND_OPERAND_C_ZERO;
cfg.internal.mode = MALI_BLEND_MODE_OPAQUE;
cfg.equation.color_mask = 0xf;
cfg.internal.fixed_function.num_comps = 4;
cfg.internal.fixed_function.rt = rt;
cfg.internal.fixed_function.conversion.memory_format =
panfrost_format_to_bifrost_blend(pdev, format, false);
cfg.internal.fixed_function.conversion.register_format =
shader_info->bifrost.blend[0].format;
}
return rsd_ptr.gpu;
}
static mali_ptr
panvk_meta_clear_zs_attachment_emit_rsd(struct panfrost_device *pdev,
struct pan_pool *desc_pool,
VkImageAspectFlags mask,
VkClearDepthStencilValue value)
{
struct panfrost_ptr rsd_ptr = pan_pool_alloc_desc(desc_pool, RENDERER_STATE);
pan_pack(rsd_ptr.cpu, RENDERER_STATE, cfg) {
cfg.properties.depth_source = MALI_DEPTH_SOURCE_FIXED_FUNCTION;
cfg.multisample_misc.sample_mask = UINT16_MAX;
if (mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
cfg.multisample_misc.depth_write_mask = true;
cfg.multisample_misc.depth_function = MALI_FUNC_NOT_EQUAL;
if (value.depth != 0.0) {
cfg.stencil_mask_misc.front_facing_depth_bias = true;
cfg.stencil_mask_misc.back_facing_depth_bias = true;
cfg.depth_units = INFINITY;
cfg.depth_bias_clamp = value.depth;
}
}
if (mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
cfg.stencil_mask_misc.stencil_enable = true;
cfg.stencil_mask_misc.stencil_mask_front = 0xFF;
cfg.stencil_mask_misc.stencil_mask_back = 0xFF;
cfg.stencil_front.compare_function =
(mask & VK_IMAGE_ASPECT_DEPTH_BIT) ?
MALI_FUNC_ALWAYS : MALI_FUNC_NOT_EQUAL;
cfg.stencil_front.stencil_fail = MALI_STENCIL_OP_KEEP;
cfg.stencil_front.depth_fail = MALI_STENCIL_OP_REPLACE;
cfg.stencil_front.depth_pass = MALI_STENCIL_OP_REPLACE;
cfg.stencil_front.reference_value = value.stencil;
cfg.stencil_front.mask = 0xFF;
cfg.stencil_back = cfg.stencil_front;
}
cfg.properties.allow_forward_pixel_to_be_killed = true;
cfg.properties.zs_update_operation = MALI_PIXEL_KILL_WEAK_EARLY;
cfg.properties.pixel_kill_operation = MALI_PIXEL_KILL_WEAK_EARLY;
}
return rsd_ptr.gpu;
}
static void
panvk_meta_clear_attachment_emit_dcd(struct pan_pool *pool,
mali_ptr coords, mali_ptr push_constants,
mali_ptr vpd, mali_ptr tsd, mali_ptr rsd,
void *out)
{
pan_pack(out, DRAW, cfg) {
cfg.thread_storage = tsd;
cfg.state = rsd;
cfg.push_uniforms = push_constants;
cfg.position = coords;
cfg.viewport = vpd;
}
}
static struct panfrost_ptr
panvk_meta_clear_attachment_emit_tiler_job(struct pan_pool *desc_pool,
struct pan_scoreboard *scoreboard,
mali_ptr coords,
mali_ptr push_constants,
mali_ptr vpd, mali_ptr rsd,
mali_ptr tsd, mali_ptr tiler)
{
struct panfrost_ptr job =
pan_pool_alloc_desc(desc_pool, TILER_JOB);
panvk_meta_clear_attachment_emit_dcd(desc_pool,
coords,
push_constants,
vpd, tsd, rsd,
pan_section_ptr(job.cpu, TILER_JOB, DRAW));
pan_section_pack(job.cpu, TILER_JOB, PRIMITIVE, cfg) {
cfg.draw_mode = MALI_DRAW_MODE_TRIANGLE_STRIP;
cfg.index_count = 4;
cfg.job_task_split = 6;
}
pan_section_pack(job.cpu, TILER_JOB, PRIMITIVE_SIZE, cfg) {
cfg.constant = 1.0f;
}
void *invoc = pan_section_ptr(job.cpu,
TILER_JOB,
INVOCATION);
panfrost_pack_work_groups_compute(invoc, 1, 4,
1, 1, 1, 1, true, false);
pan_section_pack(job.cpu, TILER_JOB, PADDING, cfg);
pan_section_pack(job.cpu, TILER_JOB, TILER, cfg) {
cfg.address = tiler;
}
panfrost_add_job(desc_pool, scoreboard, MALI_JOB_TYPE_TILER,
false, false, 0, 0, &job, false);
return job;
}
static enum glsl_base_type
panvk_meta_get_format_type(enum pipe_format format)
{
const struct util_format_description *desc = util_format_description(format);
int i;
i = util_format_get_first_non_void_channel(format);
assert(i >= 0);
if (desc->channel[i].normalized)
return GLSL_TYPE_FLOAT;
switch(desc->channel[i].type) {
case UTIL_FORMAT_TYPE_UNSIGNED:
return GLSL_TYPE_UINT;
case UTIL_FORMAT_TYPE_SIGNED:
return GLSL_TYPE_INT;
case UTIL_FORMAT_TYPE_FLOAT:
return GLSL_TYPE_FLOAT;
default:
unreachable("Unhandled format");
return GLSL_TYPE_FLOAT;
}
}
static void
panvk_meta_clear_attachment(struct panvk_cmd_buffer *cmdbuf,
unsigned attachment, unsigned rt,
VkImageAspectFlags mask,
const VkClearValue *clear_value,
const VkClearRect *clear_rect)
{
struct panvk_physical_device *dev = cmdbuf->device->physical_device;
struct panfrost_device *pdev = &dev->pdev;
struct panvk_meta *meta = &cmdbuf->device->physical_device->meta;
struct panvk_batch *batch = cmdbuf->state.batch;
const struct panvk_render_pass *pass = cmdbuf->state.pass;
const struct panvk_render_pass_attachment *att = &pass->attachments[attachment];
unsigned minx = MAX2(clear_rect->rect.offset.x, 0);
unsigned miny = MAX2(clear_rect->rect.offset.y, 0);
unsigned maxx = MAX2(clear_rect->rect.offset.x + clear_rect->rect.extent.width - 1, 0);
unsigned maxy = MAX2(clear_rect->rect.offset.y + clear_rect->rect.extent.height - 1, 0);
panvk_per_arch(cmd_alloc_fb_desc)(cmdbuf);
panvk_per_arch(cmd_alloc_tls_desc)(cmdbuf, true);
panvk_per_arch(cmd_prepare_tiler_context)(cmdbuf);
mali_ptr vpd =
panvk_per_arch(meta_emit_viewport)(&cmdbuf->desc_pool.base,
minx, miny, maxx, maxy);
float rect[] = {
minx, miny, 0.0, 1.0,
maxx + 1, miny, 0.0, 1.0,
minx, maxy + 1, 0.0, 1.0,
maxx + 1, maxy + 1, 0.0, 1.0,
};
mali_ptr coordinates = pan_pool_upload_aligned(&cmdbuf->desc_pool.base,
rect, sizeof(rect), 64);
enum glsl_base_type base_type = panvk_meta_get_format_type(att->format);
mali_ptr tiler = batch->tiler.descs.gpu;
mali_ptr tsd = batch->tls.gpu;
mali_ptr pushconsts = 0, rsd = 0;
if (mask & VK_IMAGE_ASPECT_COLOR_BIT) {
mali_ptr shader = meta->clear_attachment.color[base_type].shader;
struct pan_shader_info *shader_info = &meta->clear_attachment.color[base_type].shader_info;
pushconsts = pan_pool_upload_aligned(&cmdbuf->desc_pool.base,
clear_value, sizeof(*clear_value), 16);
rsd = panvk_meta_clear_color_attachment_emit_rsd(pdev,
&cmdbuf->desc_pool.base,
att->format, rt,
shader_info,
shader);
} else {
rsd = panvk_meta_clear_zs_attachment_emit_rsd(pdev,
&cmdbuf->desc_pool.base,
mask,
clear_value->depthStencil);
}
struct panfrost_ptr job;
job = panvk_meta_clear_attachment_emit_tiler_job(&cmdbuf->desc_pool.base,
&batch->scoreboard,
coordinates, pushconsts,
vpd, rsd, tsd, tiler);
util_dynarray_append(&batch->jobs, void *, job.cpu);
}
static void
panvk_meta_clear_color_img(struct panvk_cmd_buffer *cmdbuf,
struct panvk_image *img,
const VkClearColorValue *color,
const VkImageSubresourceRange *range)
{
struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
struct pan_image_view view = {
.format = img->pimage.layout.format,
.dim = MALI_TEXTURE_DIMENSION_2D,
.image = &img->pimage,
.nr_samples = img->pimage.layout.nr_samples,
.swizzle = { PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W },
};
cmdbuf->state.fb.crc_valid[0] = false;
*fbinfo = (struct pan_fb_info){
.nr_samples = img->pimage.layout.nr_samples,
.rt_count = 1,
.rts[0].view = &view,
.rts[0].clear = true,
.rts[0].crc_valid = &cmdbuf->state.fb.crc_valid[0],
};
uint32_t clearval[4];
pan_pack_color(clearval, (union pipe_color_union *)color,
img->pimage.layout.format, false);
memcpy(fbinfo->rts[0].clear_value, clearval, sizeof(fbinfo->rts[0].clear_value));
unsigned level_count = vk_image_subresource_level_count(&img->vk, range);
unsigned layer_count = vk_image_subresource_layer_count(&img->vk, range);
for (unsigned level = range->baseMipLevel;
level < range->baseMipLevel + level_count; level++) {
view.first_level = view.last_level = level;
fbinfo->width = u_minify(img->pimage.layout.width, level);
fbinfo->height = u_minify(img->pimage.layout.height, level);
fbinfo->extent.maxx = fbinfo->width - 1;
fbinfo->extent.maxy = fbinfo->height - 1;
for (unsigned layer = range->baseArrayLayer;
layer < range->baseArrayLayer + layer_count; layer++) {
view.first_layer = view.last_layer = layer;
panvk_cmd_open_batch(cmdbuf);
panvk_per_arch(cmd_alloc_fb_desc)(cmdbuf);
panvk_per_arch(cmd_close_batch)(cmdbuf);
}
}
}
void
panvk_per_arch(CmdClearColorImage)(VkCommandBuffer commandBuffer,
VkImage image,
VkImageLayout imageLayout,
const VkClearColorValue *pColor,
uint32_t rangeCount,
const VkImageSubresourceRange *pRanges)
{
VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
VK_FROM_HANDLE(panvk_image, img, image);
panvk_per_arch(cmd_close_batch)(cmdbuf);
for (unsigned i = 0; i < rangeCount; i++)
panvk_meta_clear_color_img(cmdbuf, img, pColor, &pRanges[i]);
}
static void
panvk_meta_clear_zs_img(struct panvk_cmd_buffer *cmdbuf,
struct panvk_image *img,
const VkClearDepthStencilValue *value,
const VkImageSubresourceRange *range)
{
struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
struct pan_image_view view = {
.format = img->pimage.layout.format,
.dim = MALI_TEXTURE_DIMENSION_2D,
.image = &img->pimage,
.nr_samples = img->pimage.layout.nr_samples,
.swizzle = { PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W },
};
cmdbuf->state.fb.crc_valid[0] = false;
*fbinfo = (struct pan_fb_info){
.nr_samples = img->pimage.layout.nr_samples,
.rt_count = 1,
.zs.clear_value.depth = value->depth,
.zs.clear_value.stencil = value->stencil,
.zs.clear.z = range->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT,
.zs.clear.s = range->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT
};
const struct util_format_description *fdesc =
util_format_description(view.format);
if (util_format_has_depth(fdesc)) {
fbinfo->zs.view.zs = &view;
if (util_format_has_stencil(fdesc)) {
fbinfo->zs.preload.z = !fbinfo->zs.clear.z;
fbinfo->zs.preload.s = !fbinfo->zs.clear.s;
}
} else {
fbinfo->zs.view.s = &view;
}
unsigned level_count = vk_image_subresource_level_count(&img->vk, range);
unsigned layer_count = vk_image_subresource_layer_count(&img->vk, range);
for (unsigned level = range->baseMipLevel;
level < range->baseMipLevel + level_count; level++) {
view.first_level = view.last_level = level;
fbinfo->width = u_minify(img->pimage.layout.width, level);
fbinfo->height = u_minify(img->pimage.layout.height, level);
fbinfo->extent.maxx = fbinfo->width - 1;
fbinfo->extent.maxy = fbinfo->height - 1;
for (unsigned layer = range->baseArrayLayer;
layer < range->baseArrayLayer + layer_count; layer++) {
view.first_layer = view.last_layer = layer;
panvk_cmd_open_batch(cmdbuf);
panvk_per_arch(cmd_alloc_fb_desc)(cmdbuf);
panvk_per_arch(cmd_close_batch)(cmdbuf);
}
}
}
void
panvk_per_arch(CmdClearDepthStencilImage)(VkCommandBuffer commandBuffer,
VkImage image,
VkImageLayout imageLayout,
const VkClearDepthStencilValue *pDepthStencil,
uint32_t rangeCount,
const VkImageSubresourceRange *pRanges)
{
VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
VK_FROM_HANDLE(panvk_image, img, image);
panvk_per_arch(cmd_close_batch)(cmdbuf);
for (unsigned i = 0; i < rangeCount; i++)
panvk_meta_clear_zs_img(cmdbuf, img, pDepthStencil, &pRanges[i]);
}
void
panvk_per_arch(CmdClearAttachments)(VkCommandBuffer commandBuffer,
uint32_t attachmentCount,
const VkClearAttachment *pAttachments,
uint32_t rectCount,
const VkClearRect *pRects)
{
VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
const struct panvk_subpass *subpass = cmdbuf->state.subpass;
for (unsigned i = 0; i < attachmentCount; i++) {
for (unsigned j = 0; j < rectCount; j++) {
uint32_t attachment, rt = 0;
if (pAttachments[i].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
rt = pAttachments[i].colorAttachment;
attachment = subpass->color_attachments[rt].idx;
} else {
attachment = subpass->zs_attachment.idx;
}
if (attachment == VK_ATTACHMENT_UNUSED)
continue;
panvk_meta_clear_attachment(cmdbuf, attachment, rt,
pAttachments[i].aspectMask,
&pAttachments[i].clearValue,
&pRects[j]);
}
}
}
static void
panvk_meta_clear_attachment_init(struct panvk_physical_device *dev)
{
dev->meta.clear_attachment.color[GLSL_TYPE_UINT].shader =
panvk_meta_clear_color_attachment_shader(
&dev->pdev,
&dev->meta.bin_pool.base,
GLSL_TYPE_UINT,
&dev->meta.clear_attachment.color[GLSL_TYPE_UINT].shader_info);
dev->meta.clear_attachment.color[GLSL_TYPE_INT].shader =
panvk_meta_clear_color_attachment_shader(
&dev->pdev,
&dev->meta.bin_pool.base,
GLSL_TYPE_INT,
&dev->meta.clear_attachment.color[GLSL_TYPE_INT].shader_info);
dev->meta.clear_attachment.color[GLSL_TYPE_FLOAT].shader =
panvk_meta_clear_color_attachment_shader(
&dev->pdev,
&dev->meta.bin_pool.base,
GLSL_TYPE_FLOAT,
&dev->meta.clear_attachment.color[GLSL_TYPE_FLOAT].shader_info);
}
void
panvk_per_arch(meta_clear_init)(struct panvk_physical_device *dev)
{
panvk_meta_clear_attachment_init(dev);
}