| /* |
| * Copyright (C) 2020 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. |
| * |
| * Authors: |
| * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> |
| */ |
| |
| #include <math.h> |
| #include <stdio.h> |
| #include "pan_encoder.h" |
| #include "pan_pool.h" |
| #include "pan_scoreboard.h" |
| #include "pan_texture.h" |
| #include "panfrost-quirks.h" |
| #include "../midgard/midgard_compile.h" |
| #include "../bifrost/bifrost_compile.h" |
| #include "compiler/nir/nir_builder.h" |
| #include "util/u_math.h" |
| |
| /* On Midgard, the native blit infrastructure (via MFBD preloads) is broken or |
| * missing in many cases. We instead use software paths as fallbacks to |
| * implement blits, which are done as TILER jobs. No vertex shader is |
| * necessary since we can supply screen-space coordinates directly. |
| * |
| * This is primarily designed as a fallback for preloads but could be extended |
| * for other clears/blits if needed in the future. */ |
| |
| static panfrost_program * |
| panfrost_build_blit_shader(struct panfrost_device *dev, |
| gl_frag_result loc, |
| nir_alu_type T, |
| bool ms) |
| { |
| bool is_colour = loc >= FRAG_RESULT_DATA0; |
| |
| nir_builder _b; |
| nir_builder_init_simple_shader(&_b, NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options); |
| nir_builder *b = &_b; |
| nir_shader *shader = b->shader; |
| |
| shader->info.internal = true; |
| |
| nir_variable *c_src = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 2), "coord"); |
| nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type( |
| GLSL_TYPE_FLOAT, is_colour ? 4 : 1), "out"); |
| |
| c_src->data.location = VARYING_SLOT_TEX0; |
| c_out->data.location = loc; |
| |
| nir_ssa_def *coord = nir_load_var(b, c_src); |
| |
| nir_tex_instr *tex = nir_tex_instr_create(shader, ms ? 3 : 1); |
| |
| tex->dest_type = T; |
| |
| if (ms) { |
| tex->src[0].src_type = nir_tex_src_coord; |
| tex->src[0].src = nir_src_for_ssa(nir_f2i32(b, coord)); |
| tex->coord_components = 2; |
| |
| tex->src[1].src_type = nir_tex_src_ms_index; |
| tex->src[1].src = nir_src_for_ssa(nir_load_sample_id(b)); |
| |
| tex->src[2].src_type = nir_tex_src_lod; |
| tex->src[2].src = nir_src_for_ssa(nir_imm_int(b, 0)); |
| tex->sampler_dim = GLSL_SAMPLER_DIM_MS; |
| tex->op = nir_texop_txf_ms; |
| } else { |
| tex->op = nir_texop_tex; |
| |
| tex->src[0].src_type = nir_tex_src_coord; |
| tex->src[0].src = nir_src_for_ssa(coord); |
| tex->coord_components = 2; |
| |
| tex->sampler_dim = GLSL_SAMPLER_DIM_2D; |
| } |
| |
| nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); |
| nir_builder_instr_insert(b, &tex->instr); |
| |
| if (is_colour) |
| nir_store_var(b, c_out, &tex->dest.ssa, 0xFF); |
| else |
| nir_store_var(b, c_out, nir_channel(b, &tex->dest.ssa, 0), 0xFF); |
| |
| struct panfrost_compile_inputs inputs = { |
| .gpu_id = dev->gpu_id, |
| }; |
| |
| panfrost_program *program; |
| |
| if (dev->quirks & IS_BIFROST) |
| program = bifrost_compile_shader_nir(NULL, shader, &inputs); |
| else |
| program = midgard_compile_shader_nir(NULL, shader, &inputs); |
| |
| ralloc_free(shader); |
| return program; |
| } |
| |
| /* Compile and upload all possible blit shaders ahead-of-time to reduce draw |
| * time overhead. There's only ~30 of them at the moment, so this is fine */ |
| |
| void |
| panfrost_init_blit_shaders(struct panfrost_device *dev) |
| { |
| bool is_bifrost = !!(dev->quirks & IS_BIFROST); |
| static const struct { |
| gl_frag_result loc; |
| unsigned types; |
| } shader_descs[] = { |
| { FRAG_RESULT_DEPTH, 1 << PAN_BLIT_FLOAT }, |
| { FRAG_RESULT_STENCIL, 1 << PAN_BLIT_UINT }, |
| { FRAG_RESULT_DATA0, ~0 }, |
| { FRAG_RESULT_DATA1, ~0 }, |
| { FRAG_RESULT_DATA2, ~0 }, |
| { FRAG_RESULT_DATA3, ~0 }, |
| { FRAG_RESULT_DATA4, ~0 }, |
| { FRAG_RESULT_DATA5, ~0 }, |
| { FRAG_RESULT_DATA6, ~0 }, |
| { FRAG_RESULT_DATA7, ~0 } |
| }; |
| |
| nir_alu_type nir_types[PAN_BLIT_NUM_TYPES] = { |
| nir_type_float, |
| nir_type_uint, |
| nir_type_int |
| }; |
| |
| /* Total size = # of shaders * bytes per shader. There are |
| * shaders for each RT (so up to DATA7 -- overestimate is |
| * okay) and up to NUM_TYPES variants of each, * 2 for multisampling |
| * variants. These shaders are simple enough that they should be less |
| * than 8 quadwords each (again, overestimate is fine). */ |
| |
| unsigned offset = 0; |
| unsigned total_size = (FRAG_RESULT_DATA7 * PAN_BLIT_NUM_TYPES) * (8 * 16) * 2; |
| |
| if (is_bifrost) |
| total_size *= 2; |
| |
| dev->blit_shaders.bo = panfrost_bo_create(dev, total_size, PAN_BO_EXECUTE); |
| |
| /* Don't bother generating multisampling variants if we don't actually |
| * support multisampling */ |
| bool has_ms = !(dev->quirks & MIDGARD_SFBD); |
| |
| for (unsigned ms = 0; ms <= has_ms; ++ms) { |
| for (unsigned i = 0; i < ARRAY_SIZE(shader_descs); ++i) { |
| unsigned loc = shader_descs[i].loc; |
| |
| for (enum pan_blit_type T = 0; T < PAN_BLIT_NUM_TYPES; ++T) { |
| if (!(shader_descs[i].types & (1 << T))) |
| continue; |
| |
| struct pan_blit_shader *shader = &dev->blit_shaders.loads[loc][T][ms]; |
| panfrost_program *program = |
| panfrost_build_blit_shader(dev, loc, |
| nir_types[T], ms); |
| |
| assert(offset + program->compiled.size < total_size); |
| memcpy(dev->blit_shaders.bo->ptr.cpu + offset, |
| program->compiled.data, program->compiled.size); |
| |
| shader->shader = (dev->blit_shaders.bo->ptr.gpu + offset) | |
| program->first_tag; |
| |
| int rt = loc - FRAG_RESULT_DATA0; |
| if (rt >= 0 && rt < 8 && program->blend_ret_offsets[rt]) |
| shader->blend_ret_addr = program->blend_ret_offsets[rt] + shader->shader; |
| |
| offset += ALIGN_POT(program->compiled.size, is_bifrost ? 128 : 64); |
| ralloc_free(program); |
| } |
| } |
| } |
| } |
| |
| static void |
| panfrost_load_emit_viewport(struct pan_pool *pool, struct MALI_DRAW *draw, |
| struct pan_image *image) |
| { |
| struct panfrost_ptr t = panfrost_pool_alloc(pool, MALI_VIEWPORT_LENGTH); |
| unsigned width = u_minify(image->width0, image->first_level); |
| unsigned height = u_minify(image->height0, image->first_level); |
| |
| pan_pack(t.cpu, VIEWPORT, cfg) { |
| cfg.scissor_maximum_x = width - 1; /* Inclusive */ |
| cfg.scissor_maximum_y = height - 1; |
| } |
| |
| draw->viewport = t.gpu; |
| } |
| |
| static void |
| panfrost_load_prepare_rsd(struct pan_pool *pool, struct MALI_RENDERER_STATE *state, |
| struct pan_image *image, unsigned loc) |
| { |
| /* Determine the sampler type needed. Stencil is always sampled as |
| * UINT. Pure (U)INT is always (U)INT. Everything else is FLOAT. */ |
| enum pan_blit_type T = |
| (loc == FRAG_RESULT_STENCIL) ? PAN_BLIT_UINT : |
| (util_format_is_pure_uint(image->format)) ? PAN_BLIT_UINT : |
| (util_format_is_pure_sint(image->format)) ? PAN_BLIT_INT : |
| PAN_BLIT_FLOAT; |
| bool ms = image->nr_samples > 1; |
| const struct pan_blit_shader *shader = |
| &pool->dev->blit_shaders.loads[loc][T][ms]; |
| |
| state->shader.shader = shader->shader; |
| assert(state->shader.shader); |
| state->shader.varying_count = 1; |
| state->shader.texture_count = 1; |
| state->shader.sampler_count = 1; |
| |
| state->properties.stencil_from_shader = (loc == FRAG_RESULT_STENCIL); |
| state->properties.depth_source = (loc == FRAG_RESULT_DEPTH) ? |
| MALI_DEPTH_SOURCE_SHADER : |
| MALI_DEPTH_SOURCE_FIXED_FUNCTION; |
| |
| state->multisample_misc.sample_mask = 0xFFFF; |
| state->multisample_misc.multisample_enable = ms; |
| state->multisample_misc.evaluate_per_sample = ms; |
| state->multisample_misc.depth_write_mask = (loc == FRAG_RESULT_DEPTH); |
| state->multisample_misc.depth_function = MALI_FUNC_ALWAYS; |
| |
| state->stencil_mask_misc.stencil_enable = (loc == FRAG_RESULT_STENCIL); |
| state->stencil_mask_misc.stencil_mask_front = 0xFF; |
| state->stencil_mask_misc.stencil_mask_back = 0xFF; |
| |
| state->stencil_front.compare_function = MALI_FUNC_ALWAYS; |
| state->stencil_front.stencil_fail = MALI_STENCIL_OP_REPLACE; |
| state->stencil_front.depth_fail = MALI_STENCIL_OP_REPLACE; |
| state->stencil_front.depth_pass = MALI_STENCIL_OP_REPLACE; |
| state->stencil_front.mask = 0xFF; |
| state->stencil_back = state->stencil_front; |
| } |
| |
| static void |
| panfrost_load_emit_varying(struct pan_pool *pool, struct MALI_DRAW *draw, |
| mali_ptr coordinates, unsigned vertex_count, |
| bool is_bifrost) |
| { |
| /* Bifrost needs an empty desc to mark end of prefetching */ |
| bool padding_buffer = is_bifrost; |
| |
| struct panfrost_ptr varying = |
| panfrost_pool_alloc(pool, MALI_ATTRIBUTE_LENGTH); |
| struct panfrost_ptr varying_buffer = |
| panfrost_pool_alloc(pool, MALI_ATTRIBUTE_BUFFER_LENGTH * |
| (padding_buffer ? 2 : 1)); |
| |
| pan_pack(varying_buffer.cpu, ATTRIBUTE_BUFFER, cfg) { |
| cfg.pointer = coordinates; |
| cfg.stride = 4 * sizeof(float); |
| cfg.size = cfg.stride * vertex_count; |
| } |
| |
| if (padding_buffer) { |
| pan_pack(varying_buffer.cpu + MALI_ATTRIBUTE_BUFFER_LENGTH, |
| ATTRIBUTE_BUFFER, cfg); |
| } |
| |
| pan_pack(varying.cpu, ATTRIBUTE, cfg) { |
| cfg.buffer_index = 0; |
| cfg.offset_enable = !is_bifrost; |
| cfg.format = (MALI_RGBA32F << 12); |
| if (pool->dev->quirks & HAS_SWIZZLES) |
| cfg.format |= panfrost_get_default_swizzle(2); |
| else |
| cfg.format |= panfrost_bifrost_swizzle(2); |
| } |
| |
| draw->varyings = varying.gpu; |
| draw->varying_buffers = varying_buffer.gpu; |
| draw->position = coordinates; |
| } |
| |
| static void |
| midgard_load_emit_texture(struct pan_pool *pool, struct MALI_DRAW *draw, |
| struct pan_image *image) |
| { |
| struct panfrost_ptr texture = |
| panfrost_pool_alloc_aligned(pool, |
| MALI_MIDGARD_TEXTURE_LENGTH + |
| sizeof(mali_ptr) * 2 * |
| MAX2(image->nr_samples, 1), |
| 128); |
| |
| struct panfrost_ptr sampler = |
| panfrost_pool_alloc(pool, MALI_MIDGARD_SAMPLER_LENGTH); |
| |
| /* Create the texture descriptor. We partially compute the base address |
| * ourselves to account for layer, such that the texture descriptor |
| * itself is for a 2D texture with array size 1 even for 3D/array |
| * textures, removing the need to separately key the blit shaders for |
| * 2D and 3D variants */ |
| panfrost_new_texture(texture.cpu, |
| image->width0, image->height0, |
| MAX2(image->nr_samples, 1), 1, |
| image->format, MALI_TEXTURE_DIMENSION_2D, |
| image->modifier, |
| image->first_level, image->last_level, |
| 0, 0, |
| image->nr_samples, |
| 0, |
| (MALI_CHANNEL_R << 0) | (MALI_CHANNEL_G << 3) | |
| (MALI_CHANNEL_B << 6) | (MALI_CHANNEL_A << 9), |
| image->bo->ptr.gpu + image->first_layer * |
| panfrost_get_layer_stride(image->slices, |
| image->dim == MALI_TEXTURE_DIMENSION_3D, |
| image->cubemap_stride, image->first_level), |
| image->slices); |
| |
| pan_pack(sampler.cpu, MIDGARD_SAMPLER, cfg) |
| cfg.normalized_coordinates = false; |
| |
| draw->textures = panfrost_pool_upload(pool, &texture.gpu, sizeof(texture.gpu)); |
| draw->samplers = sampler.gpu; |
| } |
| |
| static void |
| midgard_load_emit_blend_rt(struct pan_pool *pool, void *out, |
| mali_ptr blend_shader, struct pan_image *image, |
| unsigned rt, unsigned loc) |
| { |
| bool disabled = loc != (FRAG_RESULT_DATA0 + rt); |
| bool srgb = util_format_is_srgb(image->format); |
| |
| pan_pack(out, BLEND, cfg) { |
| if (disabled) { |
| cfg.midgard.equation.color_mask = 0xf; |
| cfg.midgard.equation.rgb.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.midgard.equation.rgb.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.midgard.equation.rgb.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.midgard.equation.alpha.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.midgard.equation.alpha.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.midgard.equation.alpha.c = MALI_BLEND_OPERAND_C_ZERO; |
| continue; |
| } |
| |
| cfg.round_to_fb_precision = true; |
| cfg.srgb = srgb; |
| |
| if (!blend_shader) { |
| cfg.midgard.equation.rgb.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.midgard.equation.rgb.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.midgard.equation.rgb.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.midgard.equation.alpha.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.midgard.equation.alpha.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.midgard.equation.alpha.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.midgard.equation.color_mask = 0xf; |
| } else { |
| cfg.midgard.blend_shader = true; |
| cfg.midgard.shader_pc = blend_shader; |
| } |
| } |
| } |
| |
| static void |
| midgard_load_emit_rsd(struct pan_pool *pool, struct MALI_DRAW *draw, |
| mali_ptr blend_shader, struct pan_image *image, |
| unsigned loc) |
| { |
| struct panfrost_ptr t = |
| panfrost_pool_alloc_aligned(pool, |
| MALI_RENDERER_STATE_LENGTH + |
| 8 * MALI_BLEND_LENGTH, |
| 128); |
| bool srgb = util_format_is_srgb(image->format); |
| |
| pan_pack(t.cpu, RENDERER_STATE, cfg) { |
| panfrost_load_prepare_rsd(pool, &cfg, image, loc); |
| cfg.properties.midgard.work_register_count = 4; |
| cfg.properties.midgard.force_early_z = (loc >= FRAG_RESULT_DATA0); |
| cfg.stencil_mask_misc.alpha_test_compare_function = MALI_FUNC_ALWAYS; |
| if (!(pool->dev->quirks & MIDGARD_SFBD)) { |
| cfg.sfbd_blend_shader = blend_shader; |
| continue; |
| } |
| |
| cfg.stencil_mask_misc.sfbd_write_enable = true; |
| cfg.stencil_mask_misc.sfbd_dither_disable = true; |
| cfg.stencil_mask_misc.sfbd_srgb = srgb; |
| cfg.multisample_misc.sfbd_blend_shader = !!blend_shader; |
| if (cfg.multisample_misc.sfbd_blend_shader) { |
| cfg.sfbd_blend_shader = blend_shader; |
| continue; |
| } |
| |
| cfg.sfbd_blend_equation.rgb.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.sfbd_blend_equation.rgb.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.sfbd_blend_equation.rgb.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.sfbd_blend_equation.alpha.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.sfbd_blend_equation.alpha.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.sfbd_blend_equation.alpha.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.sfbd_blend_constant = 0; |
| |
| if (loc >= FRAG_RESULT_DATA0) |
| cfg.sfbd_blend_equation.color_mask = 0xf; |
| } |
| |
| for (unsigned i = 0; i < 8; ++i) { |
| void *dest = t.cpu + MALI_RENDERER_STATE_LENGTH + MALI_BLEND_LENGTH * i; |
| |
| midgard_load_emit_blend_rt(pool, dest, blend_shader, image, i, loc); |
| } |
| |
| draw->state = t.gpu; |
| } |
| |
| /* Add a shader-based load on Midgard (draw-time for GL). Shaders are |
| * precached */ |
| |
| void |
| panfrost_load_midg(struct pan_pool *pool, |
| struct pan_scoreboard *scoreboard, |
| mali_ptr blend_shader, |
| mali_ptr fbd, |
| mali_ptr coordinates, unsigned vertex_count, |
| struct pan_image *image, |
| unsigned loc) |
| { |
| struct panfrost_ptr t = |
| panfrost_pool_alloc_aligned(pool, |
| MALI_MIDGARD_TILER_JOB_LENGTH, |
| 64); |
| pan_section_pack(t.cpu, MIDGARD_TILER_JOB, DRAW, cfg) { |
| cfg.texture_descriptor_is_64b = true; |
| cfg.draw_descriptor_is_64b = true; |
| cfg.four_components_per_vertex = true; |
| |
| panfrost_load_emit_varying(pool, &cfg, coordinates, vertex_count, false); |
| midgard_load_emit_texture(pool, &cfg, image); |
| panfrost_load_emit_viewport(pool, &cfg, image); |
| cfg.fbd = fbd; |
| midgard_load_emit_rsd(pool, &cfg, blend_shader, image, loc); |
| } |
| |
| pan_section_pack(t.cpu, MIDGARD_TILER_JOB, PRIMITIVE, cfg) { |
| cfg.draw_mode = MALI_DRAW_MODE_TRIANGLES; |
| cfg.index_count = vertex_count; |
| cfg.job_task_split = 6; |
| } |
| |
| pan_section_pack(t.cpu, MIDGARD_TILER_JOB, PRIMITIVE_SIZE, cfg) { |
| cfg.constant = 1.0f; |
| } |
| |
| panfrost_pack_work_groups_compute(pan_section_ptr(t.cpu, |
| MIDGARD_TILER_JOB, |
| INVOCATION), |
| 1, vertex_count, 1, 1, 1, 1, true); |
| |
| panfrost_add_job(pool, scoreboard, MALI_JOB_TYPE_TILER, false, 0, &t, true); |
| } |
| |
| static void |
| bifrost_load_emit_texture(struct pan_pool *pool, struct MALI_DRAW *draw, |
| struct pan_image *image) |
| { |
| struct panfrost_ptr texture = |
| panfrost_pool_alloc_aligned(pool, |
| MALI_BIFROST_TEXTURE_LENGTH + |
| sizeof(mali_ptr) * 2 * |
| MAX2(image->nr_samples, 1), |
| 128); |
| struct panfrost_ptr sampler = |
| panfrost_pool_alloc(pool, MALI_BIFROST_SAMPLER_LENGTH); |
| struct panfrost_ptr payload = { |
| .cpu = texture.cpu + MALI_BIFROST_TEXTURE_LENGTH, |
| .gpu = texture.gpu + MALI_BIFROST_TEXTURE_LENGTH, |
| }; |
| |
| panfrost_new_texture_bifrost(pool->dev, (void *)texture.cpu, |
| image->width0, image->height0, |
| MAX2(image->nr_samples, 1), 1, |
| image->format, MALI_TEXTURE_DIMENSION_2D, |
| image->modifier, |
| image->first_level, image->last_level, |
| 0, 0, |
| image->nr_samples, |
| 0, |
| (MALI_CHANNEL_R << 0) | (MALI_CHANNEL_G << 3) | |
| (MALI_CHANNEL_B << 6) | (MALI_CHANNEL_A << 9), |
| image->bo->ptr.gpu + image->first_layer * |
| panfrost_get_layer_stride(image->slices, |
| image->dim == MALI_TEXTURE_DIMENSION_3D, |
| image->cubemap_stride, image->first_level), |
| image->slices, |
| &payload); |
| |
| pan_pack(sampler.cpu, BIFROST_SAMPLER, cfg) { |
| cfg.seamless_cube_map = false; |
| cfg.normalized_coordinates = false; |
| cfg.point_sample_minify = true; |
| cfg.point_sample_magnify = true; |
| } |
| |
| draw->textures = texture.gpu; |
| draw->samplers = sampler.gpu; |
| } |
| |
| static enum mali_bifrost_register_file_format |
| blit_type_to_reg_fmt(enum pan_blit_type btype) |
| { |
| switch (btype) { |
| case PAN_BLIT_FLOAT: |
| return MALI_BIFROST_REGISTER_FILE_FORMAT_F32; |
| case PAN_BLIT_INT: |
| return MALI_BIFROST_REGISTER_FILE_FORMAT_I32; |
| case PAN_BLIT_UINT: |
| return MALI_BIFROST_REGISTER_FILE_FORMAT_U32; |
| default: |
| unreachable("Invalid blit type"); |
| } |
| } |
| |
| static void |
| bifrost_load_emit_blend_rt(struct pan_pool *pool, void *out, |
| mali_ptr blend_shader, struct pan_image *image, |
| unsigned rt, unsigned loc) |
| { |
| enum pan_blit_type T = |
| (loc == FRAG_RESULT_STENCIL) ? PAN_BLIT_UINT : |
| (util_format_is_pure_uint(image->format)) ? PAN_BLIT_UINT : |
| (util_format_is_pure_sint(image->format)) ? PAN_BLIT_INT : |
| PAN_BLIT_FLOAT; |
| bool disabled = loc != (FRAG_RESULT_DATA0 + rt); |
| bool srgb = util_format_is_srgb(image->format); |
| |
| pan_pack(out, BLEND, cfg) { |
| if (disabled) { |
| cfg.enable = false; |
| cfg.bifrost.internal.mode = MALI_BIFROST_BLEND_MODE_OFF; |
| continue; |
| } |
| |
| cfg.round_to_fb_precision = true; |
| cfg.srgb = srgb; |
| cfg.bifrost.internal.mode = blend_shader ? |
| MALI_BIFROST_BLEND_MODE_SHADER : |
| MALI_BIFROST_BLEND_MODE_OPAQUE; |
| if (blend_shader) { |
| cfg.bifrost.internal.shader.pc = blend_shader; |
| } else { |
| const struct util_format_description *format_desc = |
| util_format_description(image->format); |
| |
| cfg.bifrost.equation.rgb.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.bifrost.equation.rgb.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.bifrost.equation.rgb.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.bifrost.equation.alpha.a = MALI_BLEND_OPERAND_A_SRC; |
| cfg.bifrost.equation.alpha.b = MALI_BLEND_OPERAND_B_SRC; |
| cfg.bifrost.equation.alpha.c = MALI_BLEND_OPERAND_C_ZERO; |
| cfg.bifrost.equation.color_mask = 0xf; |
| cfg.bifrost.internal.fixed_function.num_comps = format_desc->nr_channels; |
| cfg.bifrost.internal.fixed_function.conversion.memory_format.format = |
| panfrost_format_to_bifrost_blend(format_desc); |
| cfg.bifrost.internal.fixed_function.conversion.register_format = |
| blit_type_to_reg_fmt(T); |
| |
| cfg.bifrost.internal.fixed_function.rt = rt; |
| if (pool->dev->quirks & HAS_SWIZZLES) { |
| cfg.bifrost.internal.fixed_function.conversion.memory_format.swizzle = |
| panfrost_get_default_swizzle(4); |
| } |
| } |
| } |
| } |
| |
| static void |
| bifrost_load_emit_rsd(struct pan_pool *pool, struct MALI_DRAW *draw, |
| mali_ptr blend_shader, struct pan_image *image, |
| unsigned loc) |
| { |
| struct panfrost_ptr t = |
| panfrost_pool_alloc_aligned(pool, |
| MALI_RENDERER_STATE_LENGTH + |
| 8 * MALI_BLEND_LENGTH, |
| 128); |
| |
| pan_pack(t.cpu, RENDERER_STATE, cfg) { |
| panfrost_load_prepare_rsd(pool, &cfg, image, loc); |
| cfg.properties.bifrost.zs_update_operation = MALI_PIXEL_KILL_STRONG_EARLY; |
| cfg.properties.bifrost.allow_forward_pixel_to_kill = true; |
| cfg.preload.fragment.coverage = true; |
| } |
| |
| for (unsigned i = 0; i < 8; ++i) { |
| void *dest = t.cpu + MALI_RENDERER_STATE_LENGTH + MALI_BLEND_LENGTH * i; |
| |
| bifrost_load_emit_blend_rt(pool, dest, blend_shader, image, i, loc); |
| } |
| |
| draw->state = t.gpu; |
| } |
| |
| void |
| panfrost_load_bifrost(struct pan_pool *pool, |
| struct pan_scoreboard *scoreboard, |
| mali_ptr blend_shader, |
| mali_ptr thread_storage, |
| mali_ptr tiler, |
| mali_ptr coordinates, unsigned vertex_count, |
| struct pan_image *image, |
| unsigned loc) |
| { |
| struct panfrost_ptr t = |
| panfrost_pool_alloc_aligned(pool, |
| MALI_BIFROST_TILER_JOB_LENGTH, |
| 64); |
| pan_section_pack(t.cpu, BIFROST_TILER_JOB, DRAW, cfg) { |
| cfg.four_components_per_vertex = true; |
| cfg.draw_descriptor_is_64b = true; |
| |
| panfrost_load_emit_varying(pool, &cfg, coordinates, vertex_count, true); |
| bifrost_load_emit_texture(pool, &cfg, image); |
| panfrost_load_emit_viewport(pool, &cfg, image); |
| cfg.thread_storage = thread_storage; |
| bifrost_load_emit_rsd(pool, &cfg, blend_shader, image, loc); |
| } |
| |
| pan_section_pack(t.cpu, BIFROST_TILER_JOB, PRIMITIVE, cfg) { |
| cfg.draw_mode = MALI_DRAW_MODE_TRIANGLES; |
| cfg.index_count = vertex_count; |
| cfg.job_task_split = 6; |
| } |
| |
| pan_section_pack(t.cpu, BIFROST_TILER_JOB, PRIMITIVE_SIZE, cfg) { |
| cfg.constant = 1.0f; |
| } |
| |
| panfrost_pack_work_groups_compute(pan_section_ptr(t.cpu, |
| MIDGARD_TILER_JOB, |
| INVOCATION), |
| 1, vertex_count, 1, 1, 1, 1, true); |
| |
| pan_section_pack(t.cpu, BIFROST_TILER_JOB, PADDING, cfg) { } |
| pan_section_pack(t.cpu, BIFROST_TILER_JOB, TILER, cfg) { |
| cfg.address = tiler; |
| } |
| |
| panfrost_add_job(pool, scoreboard, MALI_JOB_TYPE_TILER, false, 0, &t, true); |
| } |