Path: blob/21.2-virgl/src/gallium/drivers/lima/lima_draw.c
4565 views
/*1* Copyright (c) 2011-2013 Luc Verhaegen <[email protected]>2* Copyright (c) 2017-2019 Lima Project3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sub license,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the12* next paragraph) shall be included in all copies or substantial portions13* of the Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING20* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER21* DEALINGS IN THE SOFTWARE.22*23*/2425#include "util/format/u_format.h"26#include "util/u_debug.h"27#include "util/u_draw.h"28#include "util/half_float.h"29#include "util/u_helpers.h"30#include "util/u_inlines.h"31#include "util/u_pack_color.h"32#include "util/u_split_draw.h"33#include "util/u_upload_mgr.h"34#include "util/u_prim.h"35#include "util/u_vbuf.h"36#include "util/hash_table.h"3738#include "lima_context.h"39#include "lima_screen.h"40#include "lima_resource.h"41#include "lima_program.h"42#include "lima_bo.h"43#include "lima_job.h"44#include "lima_texture.h"45#include "lima_util.h"46#include "lima_gpu.h"4748#include "pan_minmax_cache.h"4950#include <drm-uapi/lima_drm.h>5152static void53lima_clip_scissor_to_viewport(struct lima_context *ctx)54{55struct lima_context_framebuffer *fb = &ctx->framebuffer;56struct pipe_scissor_state *cscissor = &ctx->clipped_scissor;57int viewport_left, viewport_right, viewport_bottom, viewport_top;5859if (ctx->rasterizer && ctx->rasterizer->base.scissor) {60struct pipe_scissor_state *scissor = &ctx->scissor;61cscissor->minx = scissor->minx;62cscissor->maxx = scissor->maxx;63cscissor->miny = scissor->miny;64cscissor->maxy = scissor->maxy;65} else {66cscissor->minx = 0;67cscissor->maxx = fb->base.width;68cscissor->miny = 0;69cscissor->maxy = fb->base.height;70}7172viewport_left = MAX2(ctx->viewport.left, 0);73cscissor->minx = MAX2(cscissor->minx, viewport_left);74viewport_right = MIN2(MAX2(ctx->viewport.right, 0), fb->base.width);75cscissor->maxx = MIN2(cscissor->maxx, viewport_right);76if (cscissor->minx > cscissor->maxx)77cscissor->minx = cscissor->maxx;7879viewport_bottom = MAX2(ctx->viewport.bottom, 0);80cscissor->miny = MAX2(cscissor->miny, viewport_bottom);81viewport_top = MIN2(MAX2(ctx->viewport.top, 0), fb->base.height);82cscissor->maxy = MIN2(cscissor->maxy, viewport_top);83if (cscissor->miny > cscissor->maxy)84cscissor->miny = cscissor->maxy;85}8687static bool88lima_is_scissor_zero(struct lima_context *ctx)89{90struct pipe_scissor_state *cscissor = &ctx->clipped_scissor;9192return cscissor->minx == cscissor->maxx || cscissor->miny == cscissor->maxy;93}9495static void96lima_update_job_wb(struct lima_context *ctx, unsigned buffers)97{98struct lima_job *job = lima_job_get(ctx);99struct lima_context_framebuffer *fb = &ctx->framebuffer;100101/* add to job when the buffer is dirty and resolve is clear (not added before) */102if (fb->base.nr_cbufs && (buffers & PIPE_CLEAR_COLOR0) &&103!(job->resolve & PIPE_CLEAR_COLOR0)) {104struct lima_resource *res = lima_resource(fb->base.cbufs[0]->texture);105lima_flush_job_accessing_bo(ctx, res->bo, true);106_mesa_hash_table_insert(ctx->write_jobs, &res->base, job);107lima_job_add_bo(job, LIMA_PIPE_PP, res->bo, LIMA_SUBMIT_BO_WRITE);108}109110/* add to job when the buffer is dirty and resolve is clear (not added before) */111if (fb->base.zsbuf && (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) &&112!(job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {113struct lima_resource *res = lima_resource(fb->base.zsbuf->texture);114lima_flush_job_accessing_bo(ctx, res->bo, true);115_mesa_hash_table_insert(ctx->write_jobs, &res->base, job);116lima_job_add_bo(job, LIMA_PIPE_PP, res->bo, LIMA_SUBMIT_BO_WRITE);117}118119job->resolve |= buffers;120}121122static void123lima_damage_rect_union(struct pipe_scissor_state *rect,124unsigned minx, unsigned maxx,125unsigned miny, unsigned maxy)126{127rect->minx = MIN2(rect->minx, minx);128rect->miny = MIN2(rect->miny, miny);129rect->maxx = MAX2(rect->maxx, maxx);130rect->maxy = MAX2(rect->maxy, maxy);131}132133static void134lima_clear(struct pipe_context *pctx, unsigned buffers, const struct pipe_scissor_state *scissor_state,135const union pipe_color_union *color, double depth, unsigned stencil)136{137struct lima_context *ctx = lima_context(pctx);138struct lima_job *job = lima_job_get(ctx);139140/* flush if this job already contains any draw, otherwise multi clear can be141* combined into a single job */142if (lima_job_has_draw_pending(job)) {143lima_do_job(job);144job = lima_job_get(ctx);145}146147lima_update_job_wb(ctx, buffers);148149/* no need to reload if cleared */150if (ctx->framebuffer.base.nr_cbufs && (buffers & PIPE_CLEAR_COLOR0)) {151struct lima_surface *surf = lima_surface(ctx->framebuffer.base.cbufs[0]);152surf->reload &= ~PIPE_CLEAR_COLOR0;153}154155struct lima_job_clear *clear = &job->clear;156clear->buffers = buffers;157158if (buffers & PIPE_CLEAR_COLOR0) {159clear->color_8pc =160((uint32_t)float_to_ubyte(color->f[3]) << 24) |161((uint32_t)float_to_ubyte(color->f[2]) << 16) |162((uint32_t)float_to_ubyte(color->f[1]) << 8) |163float_to_ubyte(color->f[0]);164165clear->color_16pc =166((uint64_t)float_to_ushort(color->f[3]) << 48) |167((uint64_t)float_to_ushort(color->f[2]) << 32) |168((uint64_t)float_to_ushort(color->f[1]) << 16) |169float_to_ushort(color->f[0]);170}171172struct lima_surface *zsbuf = lima_surface(ctx->framebuffer.base.zsbuf);173174if (buffers & PIPE_CLEAR_DEPTH) {175clear->depth = util_pack_z(PIPE_FORMAT_Z24X8_UNORM, depth);176if (zsbuf)177zsbuf->reload &= ~PIPE_CLEAR_DEPTH;178}179180if (buffers & PIPE_CLEAR_STENCIL) {181clear->stencil = stencil;182if (zsbuf)183zsbuf->reload &= ~PIPE_CLEAR_STENCIL;184}185186ctx->dirty |= LIMA_CONTEXT_DIRTY_CLEAR;187188lima_damage_rect_union(&job->damage_rect,1890, ctx->framebuffer.base.width,1900, ctx->framebuffer.base.height);191}192193enum lima_attrib_type {194LIMA_ATTRIB_FLOAT = 0x000,195LIMA_ATTRIB_I32 = 0x001,196LIMA_ATTRIB_U32 = 0x002,197LIMA_ATTRIB_FP16 = 0x003,198LIMA_ATTRIB_I16 = 0x004,199LIMA_ATTRIB_U16 = 0x005,200LIMA_ATTRIB_I8 = 0x006,201LIMA_ATTRIB_U8 = 0x007,202LIMA_ATTRIB_I8N = 0x008,203LIMA_ATTRIB_U8N = 0x009,204LIMA_ATTRIB_I16N = 0x00A,205LIMA_ATTRIB_U16N = 0x00B,206LIMA_ATTRIB_I32N = 0x00D,207LIMA_ATTRIB_U32N = 0x00E,208LIMA_ATTRIB_FIXED = 0x101209};210211static enum lima_attrib_type212lima_pipe_format_to_attrib_type(enum pipe_format format)213{214const struct util_format_description *desc = util_format_description(format);215int i = util_format_get_first_non_void_channel(format);216const struct util_format_channel_description *c = desc->channel + i;217218switch (c->type) {219case UTIL_FORMAT_TYPE_FLOAT:220if (c->size == 16)221return LIMA_ATTRIB_FP16;222else223return LIMA_ATTRIB_FLOAT;224case UTIL_FORMAT_TYPE_FIXED:225return LIMA_ATTRIB_FIXED;226case UTIL_FORMAT_TYPE_SIGNED:227if (c->size == 8) {228if (c->normalized)229return LIMA_ATTRIB_I8N;230else231return LIMA_ATTRIB_I8;232}233else if (c->size == 16) {234if (c->normalized)235return LIMA_ATTRIB_I16N;236else237return LIMA_ATTRIB_I16;238}239else if (c->size == 32) {240if (c->normalized)241return LIMA_ATTRIB_I32N;242else243return LIMA_ATTRIB_I32;244}245break;246case UTIL_FORMAT_TYPE_UNSIGNED:247if (c->size == 8) {248if (c->normalized)249return LIMA_ATTRIB_U8N;250else251return LIMA_ATTRIB_U8;252}253else if (c->size == 16) {254if (c->normalized)255return LIMA_ATTRIB_U16N;256else257return LIMA_ATTRIB_U16;258}259else if (c->size == 32) {260if (c->normalized)261return LIMA_ATTRIB_U32N;262else263return LIMA_ATTRIB_U32;264}265break;266}267268return LIMA_ATTRIB_FLOAT;269}270271static void272lima_pack_vs_cmd(struct lima_context *ctx, const struct pipe_draw_info *info,273const struct pipe_draw_start_count_bias *draw)274{275struct lima_context_constant_buffer *ccb =276ctx->const_buffer + PIPE_SHADER_VERTEX;277struct lima_vs_compiled_shader *vs = ctx->vs;278struct lima_job *job = lima_job_get(ctx);279280VS_CMD_BEGIN(&job->vs_cmd_array, 24);281282if (!info->index_size) {283VS_CMD_ARRAYS_SEMAPHORE_BEGIN_1();284VS_CMD_ARRAYS_SEMAPHORE_BEGIN_2();285}286int uniform_size = MIN2(vs->state.uniform_size, ccb->size);287288int size = uniform_size + vs->state.constant_size + 32;289VS_CMD_UNIFORMS_ADDRESS(290lima_ctx_buff_va(ctx, lima_ctx_buff_gp_uniform),291align(size, 16));292293VS_CMD_SHADER_ADDRESS(ctx->vs->bo->va, ctx->vs->state.shader_size);294VS_CMD_SHADER_INFO(ctx->vs->state.prefetch, ctx->vs->state.shader_size);295296int num_outputs = ctx->vs->state.num_outputs;297int num_attributes = ctx->vertex_elements->num_elements;298VS_CMD_VARYING_ATTRIBUTE_COUNT(num_outputs, MAX2(1, num_attributes));299300VS_CMD_UNKNOWN1();301302VS_CMD_ATTRIBUTES_ADDRESS(303lima_ctx_buff_va(ctx, lima_ctx_buff_gp_attribute_info),304MAX2(1, num_attributes));305306VS_CMD_VARYINGS_ADDRESS(307lima_ctx_buff_va(ctx, lima_ctx_buff_gp_varying_info),308num_outputs);309310unsigned num = info->index_size ? (ctx->max_index - ctx->min_index + 1) : draw->count;311VS_CMD_DRAW(num, info->index_size);312313VS_CMD_UNKNOWN2();314315VS_CMD_ARRAYS_SEMAPHORE_END(info->index_size);316317VS_CMD_END();318}319320static void321lima_pack_plbu_cmd(struct lima_context *ctx, const struct pipe_draw_info *info,322const struct pipe_draw_start_count_bias *draw)323{324struct lima_vs_compiled_shader *vs = ctx->vs;325struct pipe_scissor_state *cscissor = &ctx->clipped_scissor;326struct lima_job *job = lima_job_get(ctx);327PLBU_CMD_BEGIN(&job->plbu_cmd_array, 32);328329PLBU_CMD_VIEWPORT_LEFT(fui(ctx->viewport.left));330PLBU_CMD_VIEWPORT_RIGHT(fui(ctx->viewport.right));331PLBU_CMD_VIEWPORT_BOTTOM(fui(ctx->viewport.bottom));332PLBU_CMD_VIEWPORT_TOP(fui(ctx->viewport.top));333334if (!info->index_size)335PLBU_CMD_ARRAYS_SEMAPHORE_BEGIN();336337int cf = ctx->rasterizer->base.cull_face;338int ccw = ctx->rasterizer->base.front_ccw;339uint32_t cull = 0;340bool force_point_size = false;341342if (cf != PIPE_FACE_NONE) {343if (cf & PIPE_FACE_FRONT)344cull |= ccw ? 0x00040000 : 0x00020000;345if (cf & PIPE_FACE_BACK)346cull |= ccw ? 0x00020000 : 0x00040000;347}348349/* Specify point size with PLBU command if shader doesn't write */350if (info->mode == PIPE_PRIM_POINTS && ctx->vs->state.point_size_idx == -1)351force_point_size = true;352353/* Specify line width with PLBU command for lines */354if (info->mode > PIPE_PRIM_POINTS && info->mode < PIPE_PRIM_TRIANGLES)355force_point_size = true;356357PLBU_CMD_PRIMITIVE_SETUP(force_point_size, cull, info->index_size);358359PLBU_CMD_RSW_VERTEX_ARRAY(360lima_ctx_buff_va(ctx, lima_ctx_buff_pp_plb_rsw),361ctx->gp_output->va);362363/* TODO364* - we should set it only for the first draw that enabled the scissor and for365* latter draw only if scissor is dirty366*/367368assert(cscissor->minx < cscissor->maxx && cscissor->miny < cscissor->maxy);369PLBU_CMD_SCISSORS(cscissor->minx, cscissor->maxx, cscissor->miny, cscissor->maxy);370371lima_damage_rect_union(&job->damage_rect, cscissor->minx, cscissor->maxx,372cscissor->miny, cscissor->maxy);373374PLBU_CMD_UNKNOWN1();375376PLBU_CMD_DEPTH_RANGE_NEAR(fui(ctx->viewport.near));377PLBU_CMD_DEPTH_RANGE_FAR(fui(ctx->viewport.far));378379if ((info->mode == PIPE_PRIM_POINTS && ctx->vs->state.point_size_idx == -1) ||380((info->mode >= PIPE_PRIM_LINES) && (info->mode < PIPE_PRIM_TRIANGLES)))381{382uint32_t v = info->mode == PIPE_PRIM_POINTS ?383fui(ctx->rasterizer->base.point_size) : fui(ctx->rasterizer->base.line_width);384PLBU_CMD_LOW_PRIM_SIZE(v);385}386387if (info->index_size) {388PLBU_CMD_INDEXED_DEST(ctx->gp_output->va);389if (vs->state.point_size_idx != -1)390PLBU_CMD_INDEXED_PT_SIZE(ctx->gp_output->va + ctx->gp_output_point_size_offt);391392PLBU_CMD_INDICES(ctx->index_res->bo->va + draw->start * info->index_size + ctx->index_offset);393}394else {395/* can this make the attribute info static? */396PLBU_CMD_DRAW_ARRAYS(info->mode, draw->start, draw->count);397}398399PLBU_CMD_ARRAYS_SEMAPHORE_END();400401if (info->index_size)402PLBU_CMD_DRAW_ELEMENTS(info->mode, ctx->min_index, draw->count);403404PLBU_CMD_END();405}406407static int408lima_blend_func(enum pipe_blend_func pipe)409{410switch (pipe) {411case PIPE_BLEND_ADD:412return 2;413case PIPE_BLEND_SUBTRACT:414return 0;415case PIPE_BLEND_REVERSE_SUBTRACT:416return 1;417case PIPE_BLEND_MIN:418return 4;419case PIPE_BLEND_MAX:420return 5;421}422return -1;423}424425static int426lima_blend_factor_has_alpha(enum pipe_blendfactor pipe)427{428/* Bit 4 is set if the blendfactor uses alpha */429switch (pipe) {430case PIPE_BLENDFACTOR_SRC_ALPHA:431case PIPE_BLENDFACTOR_DST_ALPHA:432case PIPE_BLENDFACTOR_CONST_ALPHA:433case PIPE_BLENDFACTOR_INV_SRC_ALPHA:434case PIPE_BLENDFACTOR_INV_DST_ALPHA:435case PIPE_BLENDFACTOR_INV_CONST_ALPHA:436return 1;437438case PIPE_BLENDFACTOR_SRC_COLOR:439case PIPE_BLENDFACTOR_INV_SRC_COLOR:440case PIPE_BLENDFACTOR_DST_COLOR:441case PIPE_BLENDFACTOR_INV_DST_COLOR:442case PIPE_BLENDFACTOR_CONST_COLOR:443case PIPE_BLENDFACTOR_INV_CONST_COLOR:444case PIPE_BLENDFACTOR_ZERO:445case PIPE_BLENDFACTOR_ONE:446case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:447return 0;448449case PIPE_BLENDFACTOR_SRC1_COLOR:450case PIPE_BLENDFACTOR_SRC1_ALPHA:451case PIPE_BLENDFACTOR_INV_SRC1_COLOR:452case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:453return -1; /* not supported */454}455return -1;456}457458static int459lima_blend_factor_is_inv(enum pipe_blendfactor pipe)460{461/* Bit 3 is set if the blendfactor type is inverted */462switch (pipe) {463case PIPE_BLENDFACTOR_INV_SRC_COLOR:464case PIPE_BLENDFACTOR_INV_SRC_ALPHA:465case PIPE_BLENDFACTOR_INV_DST_COLOR:466case PIPE_BLENDFACTOR_INV_DST_ALPHA:467case PIPE_BLENDFACTOR_INV_CONST_COLOR:468case PIPE_BLENDFACTOR_INV_CONST_ALPHA:469case PIPE_BLENDFACTOR_ONE:470return 1;471472case PIPE_BLENDFACTOR_SRC_COLOR:473case PIPE_BLENDFACTOR_SRC_ALPHA:474case PIPE_BLENDFACTOR_DST_COLOR:475case PIPE_BLENDFACTOR_DST_ALPHA:476case PIPE_BLENDFACTOR_CONST_COLOR:477case PIPE_BLENDFACTOR_CONST_ALPHA:478case PIPE_BLENDFACTOR_ZERO:479case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:480return 0;481482case PIPE_BLENDFACTOR_SRC1_COLOR:483case PIPE_BLENDFACTOR_SRC1_ALPHA:484case PIPE_BLENDFACTOR_INV_SRC1_COLOR:485case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:486return -1; /* not supported */487}488return -1;489}490491static int492lima_blend_factor(enum pipe_blendfactor pipe)493{494/* Bits 0-2 indicate the blendfactor type */495switch (pipe) {496case PIPE_BLENDFACTOR_SRC_COLOR:497case PIPE_BLENDFACTOR_SRC_ALPHA:498case PIPE_BLENDFACTOR_INV_SRC_COLOR:499case PIPE_BLENDFACTOR_INV_SRC_ALPHA:500return 0;501502case PIPE_BLENDFACTOR_DST_COLOR:503case PIPE_BLENDFACTOR_DST_ALPHA:504case PIPE_BLENDFACTOR_INV_DST_COLOR:505case PIPE_BLENDFACTOR_INV_DST_ALPHA:506return 1;507508case PIPE_BLENDFACTOR_CONST_COLOR:509case PIPE_BLENDFACTOR_CONST_ALPHA:510case PIPE_BLENDFACTOR_INV_CONST_COLOR:511case PIPE_BLENDFACTOR_INV_CONST_ALPHA:512return 2;513514case PIPE_BLENDFACTOR_ZERO:515case PIPE_BLENDFACTOR_ONE:516return 3;517518case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:519return 4;520521case PIPE_BLENDFACTOR_SRC1_COLOR:522case PIPE_BLENDFACTOR_SRC1_ALPHA:523case PIPE_BLENDFACTOR_INV_SRC1_COLOR:524case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:525return -1; /* not supported */526}527return -1;528}529530static int531lima_calculate_alpha_blend(enum pipe_blend_func rgb_func, enum pipe_blend_func alpha_func,532enum pipe_blendfactor rgb_src_factor, enum pipe_blendfactor rgb_dst_factor,533enum pipe_blendfactor alpha_src_factor, enum pipe_blendfactor alpha_dst_factor)534{535/* PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE has to be changed to PIPE_BLENDFACTOR_ONE536* if it is set for alpha_src.537*/538if (alpha_src_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE)539alpha_src_factor = PIPE_BLENDFACTOR_ONE;540541return lima_blend_func(rgb_func) |542(lima_blend_func(alpha_func) << 3) |543544(lima_blend_factor(rgb_src_factor) << 6) |545(lima_blend_factor_is_inv(rgb_src_factor) << 9) |546(lima_blend_factor_has_alpha(rgb_src_factor) << 10) |547548(lima_blend_factor(rgb_dst_factor) << 11) |549(lima_blend_factor_is_inv(rgb_dst_factor) << 14) |550(lima_blend_factor_has_alpha(rgb_dst_factor) << 15) |551552(lima_blend_factor(alpha_src_factor) << 16) |553(lima_blend_factor_is_inv(alpha_src_factor) << 19) |554555(lima_blend_factor(alpha_dst_factor) << 20) |556(lima_blend_factor_is_inv(alpha_dst_factor) << 23) |5570x0C000000; /* need to check if this is GLESv1 glAlphaFunc */558}559560static int561lima_stencil_op(enum pipe_stencil_op pipe)562{563switch (pipe) {564case PIPE_STENCIL_OP_KEEP:565return 0;566case PIPE_STENCIL_OP_ZERO:567return 2;568case PIPE_STENCIL_OP_REPLACE:569return 1;570case PIPE_STENCIL_OP_INCR:571return 6;572case PIPE_STENCIL_OP_DECR:573return 7;574case PIPE_STENCIL_OP_INCR_WRAP:575return 4;576case PIPE_STENCIL_OP_DECR_WRAP:577return 5;578case PIPE_STENCIL_OP_INVERT:579return 3;580}581return -1;582}583584static unsigned585lima_calculate_depth_test(struct pipe_depth_stencil_alpha_state *depth,586struct pipe_rasterizer_state *rst)587{588int offset_scale = 0, offset_units = 0;589enum pipe_compare_func func = (depth->depth_enabled ? depth->depth_func : PIPE_FUNC_ALWAYS);590591offset_scale = CLAMP(rst->offset_scale * 4, -128, 127);592if (offset_scale < 0)593offset_scale += 0x100;594595offset_units = CLAMP(rst->offset_units * 2, -128, 127);596if (offset_units < 0)597offset_units += 0x100;598599return (depth->depth_enabled && depth->depth_writemask) |600((int)func << 1) |601(offset_scale << 16) |602(offset_units << 24) |6030x30; /* find out what is this */604}605606static void607lima_pack_render_state(struct lima_context *ctx, const struct pipe_draw_info *info)608{609struct lima_fs_compiled_shader *fs = ctx->fs;610struct lima_render_state *render =611lima_ctx_buff_alloc(ctx, lima_ctx_buff_pp_plb_rsw,612sizeof(*render));613bool early_z = true;614bool pixel_kill = true;615616/* do hw support RGBA independ blend?617* PIPE_CAP_INDEP_BLEND_ENABLE618*619* how to handle the no cbuf only zbuf case?620*/621struct pipe_rt_blend_state *rt = ctx->blend->base.rt;622render->blend_color_bg = float_to_ubyte(ctx->blend_color.color[2]) |623(float_to_ubyte(ctx->blend_color.color[1]) << 16);624render->blend_color_ra = float_to_ubyte(ctx->blend_color.color[0]) |625(float_to_ubyte(ctx->blend_color.color[3]) << 16);626627if (rt->blend_enable) {628render->alpha_blend = lima_calculate_alpha_blend(rt->rgb_func, rt->alpha_func,629rt->rgb_src_factor, rt->rgb_dst_factor,630rt->alpha_src_factor, rt->alpha_dst_factor);631}632else {633/*634* Special handling for blending disabled.635* Binary driver is generating the same alpha_value,636* as when we would just enable blending, without changing/setting any blend equation/params.637* Normaly in this case mesa would set all rt fields (func/factor) to zero.638*/639render->alpha_blend = lima_calculate_alpha_blend(PIPE_BLEND_ADD, PIPE_BLEND_ADD,640PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO,641PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO);642}643644render->alpha_blend |= (rt->colormask & PIPE_MASK_RGBA) << 28;645646struct pipe_rasterizer_state *rst = &ctx->rasterizer->base;647render->depth_test = lima_calculate_depth_test(&ctx->zsa->base, rst);648649ushort far, near;650651near = float_to_ushort(ctx->viewport.near);652far = float_to_ushort(ctx->viewport.far);653654/* Insert a small 'epsilon' difference between 'near' and 'far' when655* they are equal, to avoid application bugs. */656if (far == near) {657if (near > 0)658near--;659if (far < USHRT_MAX)660far++;661}662663/* overlap with plbu? any place can remove one? */664render->depth_range = near | (far << 16);665666struct pipe_stencil_state *stencil = ctx->zsa->base.stencil;667struct pipe_stencil_ref *ref = &ctx->stencil_ref;668669if (stencil[0].enabled) { /* stencil is enabled */670render->stencil_front = stencil[0].func |671(lima_stencil_op(stencil[0].fail_op) << 3) |672(lima_stencil_op(stencil[0].zfail_op) << 6) |673(lima_stencil_op(stencil[0].zpass_op) << 9) |674(ref->ref_value[0] << 16) |675(stencil[0].valuemask << 24);676render->stencil_back = render->stencil_front;677render->stencil_test = (stencil[0].writemask & 0xff) | (stencil[0].writemask & 0xff) << 8;678if (stencil[1].enabled) { /* two-side is enabled */679render->stencil_back = stencil[1].func |680(lima_stencil_op(stencil[1].fail_op) << 3) |681(lima_stencil_op(stencil[1].zfail_op) << 6) |682(lima_stencil_op(stencil[1].zpass_op) << 9) |683(ref->ref_value[1] << 16) |684(stencil[1].valuemask << 24);685render->stencil_test = (stencil[0].writemask & 0xff) | (stencil[1].writemask & 0xff) << 8;686}687/* TODO: Find out, what (render->stecil_test & 0xff000000) is */688}689else {690/* Default values, when stencil is disabled:691* stencil[0|1].valuemask = 0xff692* stencil[0|1].func = PIPE_FUNC_ALWAYS693* stencil[0|1].writemask = 0xff694*/695render->stencil_front = 0xff000007;696render->stencil_back = 0xff000007;697render->stencil_test = 0x0000ffff;698}699700/* need more investigation */701if (info->mode == PIPE_PRIM_POINTS)702render->multi_sample = 0x0000F000;703else if (info->mode < PIPE_PRIM_TRIANGLES)704render->multi_sample = 0x0000F400;705else706render->multi_sample = 0x0000F800;707if (ctx->framebuffer.base.samples)708render->multi_sample |= 0x68;709710/* alpha test */711if (ctx->zsa->base.alpha_enabled) {712render->multi_sample |= ctx->zsa->base.alpha_func;713render->stencil_test |= float_to_ubyte(ctx->zsa->base.alpha_ref_value) << 16;714} else {715/* func = PIPE_FUNC_ALWAYS */716render->multi_sample |= 0x7;717}718719render->shader_address =720ctx->fs->bo->va | (((uint32_t *)ctx->fs->bo->map)[0] & 0x1F);721722/* seems not needed */723render->uniforms_address = 0x00000000;724725render->textures_address = 0x00000000;726727render->aux0 = (ctx->vs->state.varying_stride >> 3);728render->aux1 = 0x00001000;729if (ctx->blend->base.dither)730render->aux1 |= 0x00002000;731732if (fs->state.uses_discard ||733ctx->zsa->base.alpha_enabled) {734early_z = false;735pixel_kill = false;736}737738if (rt->blend_enable)739pixel_kill = false;740741if ((rt->colormask & PIPE_MASK_RGBA) != PIPE_MASK_RGBA)742pixel_kill = false;743744if (early_z)745render->aux0 |= 0x300;746747if (pixel_kill)748render->aux0 |= 0x1000;749750if (ctx->tex_stateobj.num_samplers) {751render->textures_address =752lima_ctx_buff_va(ctx, lima_ctx_buff_pp_tex_desc);753render->aux0 |= ctx->tex_stateobj.num_samplers << 14;754render->aux0 |= 0x20;755}756757if (ctx->const_buffer[PIPE_SHADER_FRAGMENT].buffer) {758render->uniforms_address =759lima_ctx_buff_va(ctx, lima_ctx_buff_pp_uniform_array);760uint32_t size = ctx->buffer_state[lima_ctx_buff_pp_uniform].size;761uint32_t bits = 0;762if (size >= 8) {763bits = util_last_bit(size >> 3) - 1;764bits += size & u_bit_consecutive(0, bits + 3) ? 1 : 0;765}766render->uniforms_address |= bits > 0xf ? 0xf : bits;767768render->aux0 |= 0x80;769render->aux1 |= 0x10000;770}771772if (ctx->vs->state.num_varyings) {773render->varying_types = 0x00000000;774render->varyings_address = ctx->gp_output->va +775ctx->gp_output_varyings_offt;776for (int i = 0, index = 0; i < ctx->vs->state.num_outputs; i++) {777int val;778779if (i == ctx->vs->state.gl_pos_idx ||780i == ctx->vs->state.point_size_idx)781continue;782783struct lima_varying_info *v = ctx->vs->state.varying + i;784if (v->component_size == 4)785val = v->components > 2 ? 0 : 1;786else787val = v->components > 2 ? 2 : 3;788789if (index < 10)790render->varying_types |= val << (3 * index);791else if (index == 10) {792render->varying_types |= val << 30;793render->varyings_address |= val >> 2;794}795else if (index == 11)796render->varyings_address |= val << 1;797798index++;799}800}801else {802render->varying_types = 0x00000000;803render->varyings_address = 0x00000000;804}805806struct lima_job *job = lima_job_get(ctx);807808lima_dump_command_stream_print(809job->dump, render, sizeof(*render),810false, "add render state at va %x\n",811lima_ctx_buff_va(ctx, lima_ctx_buff_pp_plb_rsw));812813lima_dump_rsw_command_stream_print(814job->dump, render, sizeof(*render),815lima_ctx_buff_va(ctx, lima_ctx_buff_pp_plb_rsw));816}817818static void819lima_update_gp_attribute_info(struct lima_context *ctx, const struct pipe_draw_info *info,820const struct pipe_draw_start_count_bias *draw)821{822struct lima_job *job = lima_job_get(ctx);823struct lima_vertex_element_state *ve = ctx->vertex_elements;824struct lima_context_vertex_buffer *vb = &ctx->vertex_buffers;825826uint32_t *attribute =827lima_ctx_buff_alloc(ctx, lima_ctx_buff_gp_attribute_info,828MAX2(1, ve->num_elements) * 8);829830int n = 0;831for (int i = 0; i < ve->num_elements; i++) {832struct pipe_vertex_element *pve = ve->pipe + i;833834assert(pve->vertex_buffer_index < vb->count);835assert(vb->enabled_mask & (1 << pve->vertex_buffer_index));836837struct pipe_vertex_buffer *pvb = vb->vb + pve->vertex_buffer_index;838struct lima_resource *res = lima_resource(pvb->buffer.resource);839840lima_job_add_bo(job, LIMA_PIPE_GP, res->bo, LIMA_SUBMIT_BO_READ);841842unsigned start = info->index_size ? (ctx->min_index + draw->index_bias) : draw->start;843attribute[n++] = res->bo->va + pvb->buffer_offset + pve->src_offset844+ start * pvb->stride;845attribute[n++] = (pvb->stride << 11) |846(lima_pipe_format_to_attrib_type(pve->src_format) << 2) |847(util_format_get_nr_components(pve->src_format) - 1);848}849850lima_dump_command_stream_print(851job->dump, attribute, n * 4, false, "update attribute info at va %x\n",852lima_ctx_buff_va(ctx, lima_ctx_buff_gp_attribute_info));853}854855static void856lima_update_gp_uniform(struct lima_context *ctx)857{858struct lima_context_constant_buffer *ccb =859ctx->const_buffer + PIPE_SHADER_VERTEX;860struct lima_vs_compiled_shader *vs = ctx->vs;861int uniform_size = MIN2(vs->state.uniform_size, ccb->size);862863int size = uniform_size + vs->state.constant_size + 32;864void *vs_const_buff =865lima_ctx_buff_alloc(ctx, lima_ctx_buff_gp_uniform, size);866867if (ccb->buffer)868memcpy(vs_const_buff, ccb->buffer, uniform_size);869870memcpy(vs_const_buff + uniform_size,871ctx->viewport.transform.scale,872sizeof(ctx->viewport.transform.scale));873memcpy(vs_const_buff + uniform_size + 16,874ctx->viewport.transform.translate,875sizeof(ctx->viewport.transform.translate));876877if (vs->constant)878memcpy(vs_const_buff + uniform_size + 32,879vs->constant, vs->state.constant_size);880881struct lima_job *job = lima_job_get(ctx);882883if (lima_debug & LIMA_DEBUG_GP) {884float *vs_const_buff_f = vs_const_buff;885printf("gp uniforms:\n");886for (int i = 0; i < (size / sizeof(float)); i++) {887if ((i % 4) == 0)888printf("%4d:", i / 4);889printf(" %8.4f", vs_const_buff_f[i]);890if ((i % 4) == 3)891printf("\n");892}893printf("\n");894}895896lima_dump_command_stream_print(897job->dump, vs_const_buff, size, true,898"update gp uniform at va %x\n",899lima_ctx_buff_va(ctx, lima_ctx_buff_gp_uniform));900}901902static void903lima_update_pp_uniform(struct lima_context *ctx)904{905const float *const_buff = ctx->const_buffer[PIPE_SHADER_FRAGMENT].buffer;906size_t const_buff_size = ctx->const_buffer[PIPE_SHADER_FRAGMENT].size / sizeof(float);907908if (!const_buff)909return;910911uint16_t *fp16_const_buff =912lima_ctx_buff_alloc(ctx, lima_ctx_buff_pp_uniform,913const_buff_size * sizeof(uint16_t));914915uint32_t *array =916lima_ctx_buff_alloc(ctx, lima_ctx_buff_pp_uniform_array, 4);917918for (int i = 0; i < const_buff_size; i++)919fp16_const_buff[i] = _mesa_float_to_half(const_buff[i]);920921*array = lima_ctx_buff_va(ctx, lima_ctx_buff_pp_uniform);922923struct lima_job *job = lima_job_get(ctx);924925lima_dump_command_stream_print(926job->dump, fp16_const_buff, const_buff_size * 2,927false, "add pp uniform data at va %x\n",928lima_ctx_buff_va(ctx, lima_ctx_buff_pp_uniform));929lima_dump_command_stream_print(930job->dump, array, 4, false, "add pp uniform info at va %x\n",931lima_ctx_buff_va(ctx, lima_ctx_buff_pp_uniform_array));932}933934static void935lima_update_varying(struct lima_context *ctx, const struct pipe_draw_info *info,936const struct pipe_draw_start_count_bias *draw)937{938struct lima_job *job = lima_job_get(ctx);939struct lima_screen *screen = lima_screen(ctx->base.screen);940struct lima_vs_compiled_shader *vs = ctx->vs;941uint32_t gp_output_size;942unsigned num = info->index_size ? (ctx->max_index - ctx->min_index + 1) : draw->count;943944uint32_t *varying =945lima_ctx_buff_alloc(ctx, lima_ctx_buff_gp_varying_info,946vs->state.num_outputs * 8);947int n = 0;948949int offset = 0;950951for (int i = 0; i < vs->state.num_outputs; i++) {952struct lima_varying_info *v = vs->state.varying + i;953954if (i == vs->state.gl_pos_idx ||955i == vs->state.point_size_idx)956continue;957958int size = v->component_size * 4;959960/* does component_size == 2 need to be 16 aligned? */961if (v->component_size == 4)962offset = align(offset, 16);963964v->offset = offset;965offset += size;966}967968vs->state.varying_stride = align(offset, 16);969970/* gl_Position is always present, allocate space for it */971gp_output_size = align(4 * 4 * num, 0x40);972973/* Allocate space for varyings if there're any */974if (vs->state.num_varyings) {975ctx->gp_output_varyings_offt = gp_output_size;976gp_output_size += align(vs->state.varying_stride * num, 0x40);977}978979/* Allocate space for gl_PointSize if it's there */980if (vs->state.point_size_idx != -1) {981ctx->gp_output_point_size_offt = gp_output_size;982gp_output_size += 4 * num;983}984985/* gp_output can be too large for the suballocator, so create a986* separate bo for it. The bo cache should prevent performance hit.987*/988ctx->gp_output = lima_bo_create(screen, gp_output_size, 0);989assert(ctx->gp_output);990lima_job_add_bo(job, LIMA_PIPE_GP, ctx->gp_output, LIMA_SUBMIT_BO_WRITE);991lima_job_add_bo(job, LIMA_PIPE_PP, ctx->gp_output, LIMA_SUBMIT_BO_READ);992993for (int i = 0; i < vs->state.num_outputs; i++) {994struct lima_varying_info *v = vs->state.varying + i;995996if (i == vs->state.gl_pos_idx) {997/* gl_Position */998varying[n++] = ctx->gp_output->va;999varying[n++] = 0x8020;1000} else if (i == vs->state.point_size_idx) {1001/* gl_PointSize */1002varying[n++] = ctx->gp_output->va + ctx->gp_output_point_size_offt;1003varying[n++] = 0x2021;1004} else {1005/* Varying */1006varying[n++] = ctx->gp_output->va + ctx->gp_output_varyings_offt +1007v->offset;1008varying[n++] = (vs->state.varying_stride << 11) | (v->components - 1) |1009(v->component_size == 2 ? 0x0C : 0);1010}1011}10121013lima_dump_command_stream_print(1014job->dump, varying, n * 4, false, "update varying info at va %x\n",1015lima_ctx_buff_va(ctx, lima_ctx_buff_gp_varying_info));1016}10171018static void1019lima_draw_vbo_update(struct pipe_context *pctx,1020const struct pipe_draw_info *info,1021const struct pipe_draw_start_count_bias *draw)1022{1023struct lima_context *ctx = lima_context(pctx);1024struct lima_context_framebuffer *fb = &ctx->framebuffer;1025unsigned buffers = 0;10261027if (fb->base.zsbuf) {1028if (ctx->zsa->base.depth_enabled)1029buffers |= PIPE_CLEAR_DEPTH;1030if (ctx->zsa->base.stencil[0].enabled ||1031ctx->zsa->base.stencil[1].enabled)1032buffers |= PIPE_CLEAR_STENCIL;1033}10341035if (fb->base.nr_cbufs)1036buffers |= PIPE_CLEAR_COLOR0;10371038lima_update_job_wb(ctx, buffers);10391040lima_update_gp_attribute_info(ctx, info, draw);10411042if ((ctx->dirty & LIMA_CONTEXT_DIRTY_CONST_BUFF &&1043ctx->const_buffer[PIPE_SHADER_VERTEX].dirty) ||1044ctx->dirty & LIMA_CONTEXT_DIRTY_VIEWPORT ||1045ctx->dirty & LIMA_CONTEXT_DIRTY_COMPILED_VS) {1046lima_update_gp_uniform(ctx);1047ctx->const_buffer[PIPE_SHADER_VERTEX].dirty = false;1048}10491050lima_update_varying(ctx, info, draw);10511052lima_pack_vs_cmd(ctx, info, draw);10531054if (ctx->dirty & LIMA_CONTEXT_DIRTY_CONST_BUFF &&1055ctx->const_buffer[PIPE_SHADER_FRAGMENT].dirty) {1056lima_update_pp_uniform(ctx);1057ctx->const_buffer[PIPE_SHADER_FRAGMENT].dirty = false;1058}10591060lima_update_textures(ctx);10611062lima_pack_render_state(ctx, info);1063lima_pack_plbu_cmd(ctx, info, draw);10641065if (ctx->gp_output) {1066lima_bo_unreference(ctx->gp_output); /* held by job */1067ctx->gp_output = NULL;1068}10691070ctx->dirty = 0;1071}10721073static void1074lima_draw_vbo_indexed(struct pipe_context *pctx,1075const struct pipe_draw_info *info,1076const struct pipe_draw_start_count_bias *draw)1077{1078struct lima_context *ctx = lima_context(pctx);1079struct lima_job *job = lima_job_get(ctx);1080struct pipe_resource *indexbuf = NULL;1081bool needs_indices = true;10821083/* Mali Utgard GPU always need min/max index info for index draw,1084* compute it if upper layer does not do for us */1085if (info->index_bounds_valid) {1086ctx->min_index = info->min_index;1087ctx->max_index = info->max_index;1088needs_indices = false;1089}10901091if (info->has_user_indices) {1092util_upload_index_buffer(&ctx->base, info, draw, &indexbuf, &ctx->index_offset, 0x40);1093ctx->index_res = lima_resource(indexbuf);1094}1095else {1096ctx->index_res = lima_resource(info->index.resource);1097ctx->index_offset = 0;1098needs_indices = !panfrost_minmax_cache_get(ctx->index_res->index_cache, draw->start,1099draw->count, &ctx->min_index, &ctx->max_index);1100}11011102if (needs_indices) {1103u_vbuf_get_minmax_index(pctx, info, draw, &ctx->min_index, &ctx->max_index);1104if (!info->has_user_indices)1105panfrost_minmax_cache_add(ctx->index_res->index_cache, draw->start, draw->count,1106ctx->min_index, ctx->max_index);1107}11081109lima_job_add_bo(job, LIMA_PIPE_GP, ctx->index_res->bo, LIMA_SUBMIT_BO_READ);1110lima_job_add_bo(job, LIMA_PIPE_PP, ctx->index_res->bo, LIMA_SUBMIT_BO_READ);1111lima_draw_vbo_update(pctx, info, draw);11121113if (indexbuf)1114pipe_resource_reference(&indexbuf, NULL);1115}11161117static void1118lima_draw_vbo_count(struct pipe_context *pctx,1119const struct pipe_draw_info *info,1120const struct pipe_draw_start_count_bias *draw)1121{1122static const uint32_t max_verts = 65535;11231124struct pipe_draw_start_count_bias local_draw = *draw;1125unsigned start = draw->start;1126unsigned count = draw->count;11271128while (count) {1129unsigned this_count = count;1130unsigned step;11311132u_split_draw(info, max_verts, &this_count, &step);11331134local_draw.start = start;1135local_draw.count = this_count;11361137lima_draw_vbo_update(pctx, info, &local_draw);11381139count -= step;1140start += step;1141}1142}11431144static void1145lima_draw_vbo(struct pipe_context *pctx,1146const struct pipe_draw_info *info,1147unsigned drawid_offset,1148const struct pipe_draw_indirect_info *indirect,1149const struct pipe_draw_start_count_bias *draws,1150unsigned num_draws)1151{1152if (num_draws > 1) {1153util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);1154return;1155}11561157/* check if draw mode and vertex/index count match,1158* otherwise gp will hang */1159if (!u_trim_pipe_prim(info->mode, (unsigned*)&draws[0].count)) {1160debug_printf("draw mode and vertex/index count mismatch\n");1161return;1162}11631164struct lima_context *ctx = lima_context(pctx);11651166if (!ctx->uncomp_fs || !ctx->uncomp_vs) {1167debug_warn_once("no shader, skip draw\n");1168return;1169}11701171lima_clip_scissor_to_viewport(ctx);1172if (lima_is_scissor_zero(ctx))1173return;11741175if (!lima_update_fs_state(ctx) || !lima_update_vs_state(ctx))1176return;11771178struct lima_job *job = lima_job_get(ctx);1179job->pp_max_stack_size = MAX2(job->pp_max_stack_size, ctx->fs->state.stack_size);11801181lima_dump_command_stream_print(1182job->dump, ctx->vs->bo->map, ctx->vs->state.shader_size, false,1183"add vs at va %x\n", ctx->vs->bo->va);11841185lima_dump_command_stream_print(1186job->dump, ctx->fs->bo->map, ctx->fs->state.shader_size, false,1187"add fs at va %x\n", ctx->fs->bo->va);11881189lima_job_add_bo(job, LIMA_PIPE_GP, ctx->vs->bo, LIMA_SUBMIT_BO_READ);1190lima_job_add_bo(job, LIMA_PIPE_PP, ctx->fs->bo, LIMA_SUBMIT_BO_READ);11911192if (info->index_size)1193lima_draw_vbo_indexed(pctx, info, &draws[0]);1194else1195lima_draw_vbo_count(pctx, info, &draws[0]);11961197job->draws++;1198/* Flush job if we hit the limit of draws per job otherwise we may1199* hit tile heap size limit */1200if (job->draws > MAX_DRAWS_PER_JOB) {1201unsigned resolve = job->resolve;1202lima_do_job(job);1203job = lima_job_get(ctx);1204/* Subsequent job will need to resolve the same buffers */1205lima_update_job_wb(ctx, resolve);1206}1207}12081209void1210lima_draw_init(struct lima_context *ctx)1211{1212ctx->base.clear = lima_clear;1213ctx->base.draw_vbo = lima_draw_vbo;1214}121512161217