Path: blob/21.2-virgl/src/gallium/drivers/asahi/agx_state.c
4570 views
/*1* Copyright 2021 Alyssa Rosenzweig2* Copyright (C) 2019-2020 Collabora, Ltd.3* Copyright 2010 Red Hat Inc.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the "Software"),7* to deal in the Software without restriction, including without limitation8* on the rights to use, copy, modify, merge, publish, distribute, sub9* license, and/or sell copies of the Software, and to permit persons to whom10* the Software is furnished to do so, subject to the following conditions:11*12* The above copyright notice and this permission notice (including the next13* paragraph) shall be included in all copies or substantial portions of the14* Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL19* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,20* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR21* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE22* USE OR OTHER DEALINGS IN THE SOFTWARE.23*/24#include <stdio.h>25#include <errno.h>26#include "pipe/p_defines.h"27#include "pipe/p_state.h"28#include "pipe/p_context.h"29#include "pipe/p_screen.h"30#include "util/u_memory.h"31#include "util/u_inlines.h"32#include "util/u_transfer.h"33#include "gallium/auxiliary/util/u_draw.h"34#include "gallium/auxiliary/util/u_helpers.h"35#include "gallium/auxiliary/util/u_viewport.h"36#include "gallium/auxiliary/util/u_blend.h"37#include "gallium/auxiliary/util/u_framebuffer.h"38#include "gallium/auxiliary/tgsi/tgsi_from_mesa.h"39#include "gallium/auxiliary/nir/tgsi_to_nir.h"40#include "compiler/nir/nir.h"41#include "asahi/compiler/agx_compile.h"42#include "agx_state.h"43#include "asahi/lib/agx_pack.h"44#include "asahi/lib/agx_formats.h"4546static struct pipe_stream_output_target *47agx_create_stream_output_target(struct pipe_context *pctx,48struct pipe_resource *prsc,49unsigned buffer_offset,50unsigned buffer_size)51{52struct pipe_stream_output_target *target;5354target = &rzalloc(pctx, struct agx_streamout_target)->base;5556if (!target)57return NULL;5859pipe_reference_init(&target->reference, 1);60pipe_resource_reference(&target->buffer, prsc);6162target->context = pctx;63target->buffer_offset = buffer_offset;64target->buffer_size = buffer_size;6566return target;67}6869static void70agx_stream_output_target_destroy(struct pipe_context *pctx,71struct pipe_stream_output_target *target)72{73pipe_resource_reference(&target->buffer, NULL);74ralloc_free(target);75}7677static void78agx_set_stream_output_targets(struct pipe_context *pctx,79unsigned num_targets,80struct pipe_stream_output_target **targets,81const unsigned *offsets)82{83struct agx_context *ctx = agx_context(pctx);84struct agx_streamout *so = &ctx->streamout;8586assert(num_targets <= ARRAY_SIZE(so->targets));8788for (unsigned i = 0; i < num_targets; i++) {89if (offsets[i] != -1)90agx_so_target(targets[i])->offset = offsets[i];9192pipe_so_target_reference(&so->targets[i], targets[i]);93}9495for (unsigned i = 0; i < so->num_targets; i++)96pipe_so_target_reference(&so->targets[i], NULL);9798so->num_targets = num_targets;99}100101static void102agx_set_blend_color(struct pipe_context *pctx,103const struct pipe_blend_color *state)104{105struct agx_context *ctx = agx_context(pctx);106107if (state)108memcpy(&ctx->blend_color, state, sizeof(*state));109}110111static void *112agx_create_blend_state(struct pipe_context *ctx,113const struct pipe_blend_state *state)114{115struct agx_blend *so = CALLOC_STRUCT(agx_blend);116117assert(!state->alpha_to_coverage);118assert(!state->alpha_to_coverage_dither);119assert(!state->alpha_to_one);120assert(!state->advanced_blend_func);121122if (state->logicop_enable) {123so->logicop_enable = true;124so->logicop_func = state->logicop_func;125return so;126}127128for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {129unsigned rti = state->independent_blend_enable ? i : 0;130struct pipe_rt_blend_state rt = state->rt[rti];131132if (!rt.blend_enable) {133static const nir_lower_blend_channel replace = {134.func = BLEND_FUNC_ADD,135.src_factor = BLEND_FACTOR_ZERO,136.invert_src_factor = true,137.dst_factor = BLEND_FACTOR_ZERO,138.invert_dst_factor = false,139};140141so->rt[i].rgb = replace;142so->rt[i].alpha = replace;143} else {144so->rt[i].rgb.func = util_blend_func_to_shader(rt.rgb_func);145so->rt[i].rgb.src_factor = util_blend_factor_to_shader(rt.rgb_src_factor);146so->rt[i].rgb.invert_src_factor = util_blend_factor_is_inverted(rt.rgb_src_factor);147so->rt[i].rgb.dst_factor = util_blend_factor_to_shader(rt.rgb_dst_factor);148so->rt[i].rgb.invert_dst_factor = util_blend_factor_is_inverted(rt.rgb_dst_factor);149150so->rt[i].alpha.func = util_blend_func_to_shader(rt.alpha_func);151so->rt[i].alpha.src_factor = util_blend_factor_to_shader(rt.alpha_src_factor);152so->rt[i].alpha.invert_src_factor = util_blend_factor_is_inverted(rt.alpha_src_factor);153so->rt[i].alpha.dst_factor = util_blend_factor_to_shader(rt.alpha_dst_factor);154so->rt[i].alpha.invert_dst_factor = util_blend_factor_is_inverted(rt.alpha_dst_factor);155156so->blend_enable = true;157}158159so->rt[i].colormask = rt.colormask;160}161162return so;163}164165static void166agx_bind_blend_state(struct pipe_context *pctx, void *cso)167{168struct agx_context *ctx = agx_context(pctx);169ctx->blend = cso;170}171172static const enum agx_stencil_op agx_stencil_ops[PIPE_STENCIL_OP_INVERT + 1] = {173[PIPE_STENCIL_OP_KEEP] = AGX_STENCIL_OP_KEEP,174[PIPE_STENCIL_OP_ZERO] = AGX_STENCIL_OP_ZERO,175[PIPE_STENCIL_OP_REPLACE] = AGX_STENCIL_OP_REPLACE,176[PIPE_STENCIL_OP_INCR] = AGX_STENCIL_OP_INCR_SAT,177[PIPE_STENCIL_OP_DECR] = AGX_STENCIL_OP_DECR_SAT,178[PIPE_STENCIL_OP_INCR_WRAP] = AGX_STENCIL_OP_INCR_WRAP,179[PIPE_STENCIL_OP_DECR_WRAP] = AGX_STENCIL_OP_DECR_WRAP,180[PIPE_STENCIL_OP_INVERT] = AGX_STENCIL_OP_INVERT,181};182183static void184agx_pack_rasterizer_face(struct agx_rasterizer_face_packed *out,185struct pipe_stencil_state st,186enum agx_zs_func z_func,187bool disable_z_write)188{189agx_pack(out, RASTERIZER_FACE, cfg) {190cfg.depth_function = z_func;191cfg.disable_depth_write = disable_z_write;192193if (st.enabled) {194cfg.stencil_write_mask = st.writemask;195cfg.stencil_read_mask = st.valuemask;196197cfg.depth_pass = agx_stencil_ops[st.zpass_op];198cfg.depth_fail = agx_stencil_ops[st.zfail_op];199cfg.stencil_fail = agx_stencil_ops[st.fail_op];200201cfg.stencil_compare = (enum agx_zs_func) st.func;202} else {203cfg.stencil_write_mask = 0xFF;204cfg.stencil_read_mask = 0xFF;205206cfg.depth_pass = AGX_STENCIL_OP_KEEP;207cfg.depth_fail = AGX_STENCIL_OP_KEEP;208cfg.stencil_fail = AGX_STENCIL_OP_KEEP;209210cfg.stencil_compare = AGX_ZS_FUNC_ALWAYS;211}212}213}214215static void *216agx_create_zsa_state(struct pipe_context *ctx,217const struct pipe_depth_stencil_alpha_state *state)218{219struct agx_zsa *so = CALLOC_STRUCT(agx_zsa);220assert(!state->depth_bounds_test && "todo");221222so->base = *state;223224/* Z func can be used as-is */225STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_NEVER == AGX_ZS_FUNC_NEVER);226STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_LESS == AGX_ZS_FUNC_LESS);227STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_EQUAL == AGX_ZS_FUNC_EQUAL);228STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_LEQUAL == AGX_ZS_FUNC_LEQUAL);229STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_GREATER == AGX_ZS_FUNC_GREATER);230STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_NOTEQUAL == AGX_ZS_FUNC_NOT_EQUAL);231STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_GEQUAL == AGX_ZS_FUNC_GEQUAL);232STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_ALWAYS == AGX_ZS_FUNC_ALWAYS);233234enum agx_zs_func z_func = state->depth_enabled ?235((enum agx_zs_func) state->depth_func) : AGX_ZS_FUNC_ALWAYS;236237agx_pack_rasterizer_face(&so->front,238state->stencil[0], z_func, !state->depth_writemask);239240if (state->stencil[1].enabled) {241agx_pack_rasterizer_face(&so->back,242state->stencil[1], z_func, !state->depth_writemask);243} else {244/* One sided stencil */245so->back = so->front;246}247248return so;249}250251static void252agx_bind_zsa_state(struct pipe_context *pctx, void *cso)253{254struct agx_context *ctx = agx_context(pctx);255256if (cso)257memcpy(&ctx->zs, cso, sizeof(ctx->zs));258}259260static void *261agx_create_rs_state(struct pipe_context *ctx,262const struct pipe_rasterizer_state *cso)263{264struct agx_rasterizer *so = CALLOC_STRUCT(agx_rasterizer);265so->base = *cso;266267/* Line width is packed in a 4:4 fixed point format */268unsigned line_width_fixed = ((unsigned) (cso->line_width * 16.0f)) - 1;269270/* Clamp to maximum line width */271so->line_width = MIN2(line_width_fixed, 0xFF);272273agx_pack(so->cull, CULL, cfg) {274cfg.cull_front = cso->cull_face & PIPE_FACE_FRONT;275cfg.cull_back = cso->cull_face & PIPE_FACE_BACK;276cfg.front_face_ccw = cso->front_ccw;277cfg.depth_clip = cso->depth_clip_near;278cfg.depth_clamp = !cso->depth_clip_near;279};280281return so;282}283284static void285agx_bind_rasterizer_state(struct pipe_context *pctx, void *cso)286{287struct agx_context *ctx = agx_context(pctx);288struct agx_rasterizer *so = cso;289290/* Check if scissor state has changed, since scissor enable is part of the291* rasterizer state but everything else needed for scissors is part of292* viewport/scissor states */293bool scissor_changed = (cso == NULL) || (ctx->rast == NULL) ||294(ctx->rast->base.scissor != so->base.scissor);295296ctx->rast = so;297298if (scissor_changed)299ctx->dirty |= AGX_DIRTY_SCISSOR;300}301302static enum agx_wrap303agx_wrap_from_pipe(enum pipe_tex_wrap in)304{305switch (in) {306case PIPE_TEX_WRAP_REPEAT: return AGX_WRAP_REPEAT;307case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return AGX_WRAP_CLAMP_TO_EDGE;308case PIPE_TEX_WRAP_MIRROR_REPEAT: return AGX_WRAP_MIRRORED_REPEAT;309case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return AGX_WRAP_CLAMP_TO_BORDER;310default: unreachable("todo: more wrap modes");311}312}313314static enum agx_mip_filter315agx_mip_filter_from_pipe(enum pipe_tex_mipfilter in)316{317switch (in) {318case PIPE_TEX_MIPFILTER_NEAREST: return AGX_MIP_FILTER_NEAREST;319case PIPE_TEX_MIPFILTER_LINEAR: return AGX_MIP_FILTER_LINEAR;320case PIPE_TEX_MIPFILTER_NONE: return AGX_MIP_FILTER_NONE;321}322323unreachable("Invalid mip filter");324}325326static const enum agx_compare_func agx_compare_funcs[PIPE_FUNC_ALWAYS + 1] = {327[PIPE_FUNC_NEVER] = AGX_COMPARE_FUNC_NEVER,328[PIPE_FUNC_LESS] = AGX_COMPARE_FUNC_LESS,329[PIPE_FUNC_EQUAL] = AGX_COMPARE_FUNC_EQUAL,330[PIPE_FUNC_LEQUAL] = AGX_COMPARE_FUNC_LEQUAL,331[PIPE_FUNC_GREATER] = AGX_COMPARE_FUNC_GREATER,332[PIPE_FUNC_NOTEQUAL] = AGX_COMPARE_FUNC_NOT_EQUAL,333[PIPE_FUNC_GEQUAL] = AGX_COMPARE_FUNC_GEQUAL,334[PIPE_FUNC_ALWAYS] = AGX_COMPARE_FUNC_ALWAYS,335};336337static void *338agx_create_sampler_state(struct pipe_context *pctx,339const struct pipe_sampler_state *state)340{341struct agx_device *dev = agx_device(pctx->screen);342struct agx_bo *bo = agx_bo_create(dev, AGX_SAMPLER_LENGTH,343AGX_MEMORY_TYPE_FRAMEBUFFER);344345assert(state->min_lod == 0 && "todo: lod clamps");346assert(state->lod_bias == 0 && "todo: lod bias");347348agx_pack(bo->ptr.cpu, SAMPLER, cfg) {349cfg.magnify_linear = (state->mag_img_filter == PIPE_TEX_FILTER_LINEAR);350cfg.minify_linear = (state->min_img_filter == PIPE_TEX_FILTER_LINEAR);351cfg.mip_filter = agx_mip_filter_from_pipe(state->min_mip_filter);352cfg.wrap_s = agx_wrap_from_pipe(state->wrap_s);353cfg.wrap_t = agx_wrap_from_pipe(state->wrap_t);354cfg.wrap_r = agx_wrap_from_pipe(state->wrap_r);355cfg.pixel_coordinates = !state->normalized_coords;356cfg.compare_func = agx_compare_funcs[state->compare_func];357}358359struct agx_sampler_state *so = CALLOC_STRUCT(agx_sampler_state);360so->base = *state;361so->desc = bo;362363return so;364}365366static void367agx_delete_sampler_state(struct pipe_context *ctx, void *state)368{369struct agx_bo *bo = state;370agx_bo_unreference(bo);371}372373static void374agx_bind_sampler_states(struct pipe_context *pctx,375enum pipe_shader_type shader,376unsigned start, unsigned count,377void **states)378{379struct agx_context *ctx = agx_context(pctx);380381ctx->stage[shader].sampler_count = states ? count : 0;382383memcpy(&ctx->stage[shader].samplers[start], states,384sizeof(struct agx_sampler_state *) * count);385}386387/* Channels agree for RGBA but are weird for force 0/1 */388389static enum agx_channel390agx_channel_from_pipe(enum pipe_swizzle in)391{392STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_X == AGX_CHANNEL_R);393STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_Y == AGX_CHANNEL_G);394STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_Z == AGX_CHANNEL_B);395STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_W == AGX_CHANNEL_A);396STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_0 & 0x4);397STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_1 & 0x4);398STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_NONE & 0x4);399400if ((in & 0x4) == 0)401return (enum agx_channel) in;402else if (in == PIPE_SWIZZLE_1)403return AGX_CHANNEL_1;404else405return AGX_CHANNEL_0;406}407408static enum agx_layout409agx_translate_layout(uint64_t modifier)410{411switch (modifier) {412case DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER:413return AGX_LAYOUT_TILED_64X64;414case DRM_FORMAT_MOD_LINEAR:415return AGX_LAYOUT_LINEAR;416default:417unreachable("Invalid modifier");418}419}420421static struct pipe_sampler_view *422agx_create_sampler_view(struct pipe_context *pctx,423struct pipe_resource *texture,424const struct pipe_sampler_view *state)425{426struct agx_device *dev = agx_device(pctx->screen);427struct agx_resource *rsrc = agx_resource(texture);428struct agx_sampler_view *so = CALLOC_STRUCT(agx_sampler_view);429430if (!so)431return NULL;432433/* We prepare the descriptor at CSO create time */434so->desc = agx_bo_create(dev, AGX_TEXTURE_LENGTH,435AGX_MEMORY_TYPE_FRAMEBUFFER);436437const struct util_format_description *desc =438util_format_description(state->format);439440/* We only have a single swizzle for the user swizzle and the format fixup,441* so compose them now. */442uint8_t out_swizzle[4];443uint8_t view_swizzle[4] = {444state->swizzle_r, state->swizzle_g,445state->swizzle_b, state->swizzle_a446};447448util_format_compose_swizzles(desc->swizzle, view_swizzle, out_swizzle);449450unsigned level = state->u.tex.first_level;451452/* Pack the descriptor into GPU memory */453agx_pack(so->desc->ptr.cpu, TEXTURE, cfg) {454cfg.layout = agx_translate_layout(rsrc->modifier);455cfg.format = agx_pixel_format[state->format].hw;456cfg.swizzle_r = agx_channel_from_pipe(out_swizzle[0]);457cfg.swizzle_g = agx_channel_from_pipe(out_swizzle[1]);458cfg.swizzle_b = agx_channel_from_pipe(out_swizzle[2]);459cfg.swizzle_a = agx_channel_from_pipe(out_swizzle[3]);460cfg.width = u_minify(texture->width0, level);461cfg.height = u_minify(texture->height0, level);462cfg.levels = state->u.tex.last_level - level + 1;463cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);464cfg.unk_1 = rsrc->bo->ptr.gpu + rsrc->slices[level].offset;465cfg.unk_2 = false;466467cfg.stride = (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) ?468(rsrc->slices[level].line_stride - 16) :469AGX_RT_STRIDE_TILED;470}471472/* Initialize base object */473so->base = *state;474so->base.texture = NULL;475pipe_resource_reference(&so->base.texture, texture);476pipe_reference_init(&so->base.reference, 1);477so->base.context = pctx;478return &so->base;479}480481static void482agx_set_sampler_views(struct pipe_context *pctx,483enum pipe_shader_type shader,484unsigned start, unsigned count,485unsigned unbind_num_trailing_slots,486struct pipe_sampler_view **views)487{488struct agx_context *ctx = agx_context(pctx);489unsigned new_nr = 0;490unsigned i;491492assert(start == 0);493494if (!views)495count = 0;496497for (i = 0; i < count; ++i) {498if (views[i])499new_nr = i + 1;500501pipe_sampler_view_reference((struct pipe_sampler_view **)502&ctx->stage[shader].textures[i], views[i]);503}504505for (; i < ctx->stage[shader].texture_count; i++) {506pipe_sampler_view_reference((struct pipe_sampler_view **)507&ctx->stage[shader].textures[i], NULL);508}509ctx->stage[shader].texture_count = new_nr;510}511512static void513agx_sampler_view_destroy(struct pipe_context *ctx,514struct pipe_sampler_view *pview)515{516struct agx_sampler_view *view = (struct agx_sampler_view *) pview;517pipe_resource_reference(&view->base.texture, NULL);518agx_bo_unreference(view->desc);519FREE(view);520}521522static struct pipe_surface *523agx_create_surface(struct pipe_context *ctx,524struct pipe_resource *texture,525const struct pipe_surface *surf_tmpl)526{527struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);528529if (!surface)530return NULL;531pipe_reference_init(&surface->reference, 1);532pipe_resource_reference(&surface->texture, texture);533surface->context = ctx;534surface->format = surf_tmpl->format;535surface->width = texture->width0;536surface->height = texture->height0;537surface->texture = texture;538surface->u.tex.first_layer = surf_tmpl->u.tex.first_layer;539surface->u.tex.last_layer = surf_tmpl->u.tex.last_layer;540surface->u.tex.level = surf_tmpl->u.tex.level;541542return surface;543}544545static void546agx_set_clip_state(struct pipe_context *ctx,547const struct pipe_clip_state *state)548{549}550551static void552agx_set_polygon_stipple(struct pipe_context *ctx,553const struct pipe_poly_stipple *state)554{555}556557static void558agx_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask)559{560struct agx_context *ctx = agx_context(pipe);561ctx->sample_mask = sample_mask;562}563564static void565agx_set_scissor_states(struct pipe_context *pctx,566unsigned start_slot,567unsigned num_scissors,568const struct pipe_scissor_state *scissor)569{570struct agx_context *ctx = agx_context(pctx);571572assert(start_slot == 0 && "no geometry shaders");573assert(num_scissors == 1 && "no geometry shaders");574575ctx->scissor = *scissor;576ctx->dirty |= AGX_DIRTY_SCISSOR;577}578579static void580agx_set_stencil_ref(struct pipe_context *pctx,581const struct pipe_stencil_ref state)582{583struct agx_context *ctx = agx_context(pctx);584ctx->stencil_ref = state;585}586587static void588agx_set_viewport_states(struct pipe_context *pctx,589unsigned start_slot,590unsigned num_viewports,591const struct pipe_viewport_state *vp)592{593struct agx_context *ctx = agx_context(pctx);594595assert(start_slot == 0 && "no geometry shaders");596assert(num_viewports == 1 && "no geometry shaders");597598ctx->dirty |= AGX_DIRTY_VIEWPORT;599ctx->viewport = *vp;600}601602struct agx_viewport_scissor {603uint64_t viewport;604unsigned scissor;605};606607static struct agx_viewport_scissor608agx_upload_viewport_scissor(struct agx_pool *pool,609struct agx_batch *batch,610const struct pipe_viewport_state *vp,611const struct pipe_scissor_state *ss)612{613struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_VIEWPORT_LENGTH, 64);614615float trans_x = vp->translate[0], trans_y = vp->translate[1];616float abs_scale_x = fabsf(vp->scale[0]), abs_scale_y = fabsf(vp->scale[1]);617618/* Calculate the extent of the viewport. Note if a particular dimension of619* the viewport is an odd number of pixels, both the translate and the scale620* will have a fractional part of 0.5, so adding and subtracting them yields621* an integer. Therefore we don't need to round explicitly */622unsigned minx = CLAMP((int) (trans_x - abs_scale_x), 0, batch->width);623unsigned miny = CLAMP((int) (trans_y - abs_scale_y), 0, batch->height);624unsigned maxx = CLAMP((int) (trans_x + abs_scale_x), 0, batch->width);625unsigned maxy = CLAMP((int) (trans_y + abs_scale_y), 0, batch->height);626627if (ss) {628minx = MAX2(ss->minx, minx);629miny = MAX2(ss->miny, miny);630maxx = MIN2(ss->maxx, maxx);631maxy = MIN2(ss->maxy, maxy);632}633634assert(maxx > minx && maxy > miny);635636float minz, maxz;637util_viewport_zmin_zmax(vp, false, &minz, &maxz);638639agx_pack(T.cpu, VIEWPORT, cfg) {640cfg.min_tile_x = minx / 32;641cfg.min_tile_y = miny / 32;642cfg.max_tile_x = DIV_ROUND_UP(maxx, 32);643cfg.max_tile_y = DIV_ROUND_UP(maxy, 32);644cfg.clip_tile = true;645646cfg.translate_x = vp->translate[0];647cfg.translate_y = vp->translate[1];648cfg.scale_x = vp->scale[0];649cfg.scale_y = vp->scale[1];650651/* Assumes [0, 1] clip coordinates. If half-z is not in use, lower_half_z652* is called to ensure this works. */653cfg.translate_z = minz;654cfg.scale_z = maxz - minz;655};656657/* Allocate a new scissor descriptor */658struct agx_scissor_packed *ptr = batch->scissor.bo->ptr.cpu;659unsigned index = (batch->scissor.count++);660661agx_pack(ptr + index, SCISSOR, cfg) {662cfg.min_x = minx;663cfg.min_y = miny;664cfg.min_z = minz;665cfg.max_x = maxx;666cfg.max_y = maxy;667cfg.max_z = maxz;668}669670return (struct agx_viewport_scissor) {671.viewport = T.gpu,672.scissor = index673};674}675676/* A framebuffer state can be reused across batches, so it doesn't make sense677* to add surfaces to the BO list here. Instead we added them when flushing.678*/679680static void681agx_set_framebuffer_state(struct pipe_context *pctx,682const struct pipe_framebuffer_state *state)683{684struct agx_context *ctx = agx_context(pctx);685686if (!state)687return;688689/* XXX: eliminate this flush with batch tracking logic */690pctx->flush(pctx, NULL, 0);691692util_copy_framebuffer_state(&ctx->framebuffer, state);693ctx->batch->width = state->width;694ctx->batch->height = state->height;695ctx->batch->nr_cbufs = state->nr_cbufs;696ctx->batch->cbufs[0] = state->cbufs[0];697ctx->batch->zsbuf = state->zsbuf;698ctx->dirty = ~0;699700for (unsigned i = 0; i < state->nr_cbufs; ++i) {701struct pipe_surface *surf = state->cbufs[i];702struct agx_resource *tex = agx_resource(surf->texture);703const struct util_format_description *desc =704util_format_description(surf->format);705706agx_pack(ctx->render_target[i], RENDER_TARGET, cfg) {707cfg.layout = agx_translate_layout(tex->modifier);708cfg.format = agx_pixel_format[surf->format].hw;709cfg.swizzle_r = agx_channel_from_pipe(desc->swizzle[0]);710cfg.swizzle_g = agx_channel_from_pipe(desc->swizzle[1]);711cfg.swizzle_b = agx_channel_from_pipe(desc->swizzle[2]);712cfg.swizzle_a = agx_channel_from_pipe(desc->swizzle[3]);713cfg.width = state->width;714cfg.height = state->height;715cfg.buffer = tex->bo->ptr.gpu;716717cfg.stride = (tex->modifier == DRM_FORMAT_MOD_LINEAR) ?718(tex->slices[0].line_stride - 4) :719AGX_RT_STRIDE_TILED;720};721}722}723724/* Likewise constant buffers, textures, and samplers are handled in a common725* per-draw path, with dirty tracking to reduce the costs involved.726*/727728static void729agx_set_constant_buffer(struct pipe_context *pctx,730enum pipe_shader_type shader, uint index,731bool take_ownership,732const struct pipe_constant_buffer *cb)733{734struct agx_context *ctx = agx_context(pctx);735struct agx_stage *s = &ctx->stage[shader];736737util_copy_constant_buffer(&s->cb[index], cb, take_ownership);738739unsigned mask = (1 << index);740741if (cb)742s->cb_mask |= mask;743else744s->cb_mask &= ~mask;745}746747static void748agx_surface_destroy(struct pipe_context *ctx,749struct pipe_surface *surface)750{751pipe_resource_reference(&surface->texture, NULL);752FREE(surface);753}754755static void756agx_delete_state(struct pipe_context *ctx, void *state)757{758FREE(state);759}760761/* BOs added to the batch in the uniform upload path */762763static void764agx_set_vertex_buffers(struct pipe_context *pctx,765unsigned start_slot, unsigned count,766unsigned unbind_num_trailing_slots,767bool take_ownership,768const struct pipe_vertex_buffer *buffers)769{770struct agx_context *ctx = agx_context(pctx);771772util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx->vb_mask, buffers,773start_slot, count, unbind_num_trailing_slots, take_ownership);774775ctx->dirty |= AGX_DIRTY_VERTEX;776}777778static void *779agx_create_vertex_elements(struct pipe_context *ctx,780unsigned count,781const struct pipe_vertex_element *state)782{783assert(count < AGX_MAX_ATTRIBS);784785struct agx_attribute *attribs = calloc(sizeof(*attribs), AGX_MAX_ATTRIBS);786for (unsigned i = 0; i < count; ++i) {787const struct pipe_vertex_element ve = state[i];788assert(ve.instance_divisor == 0 && "no instancing");789790const struct util_format_description *desc =791util_format_description(ve.src_format);792793assert(desc->nr_channels >= 1 && desc->nr_channels <= 4);794assert((ve.src_offset & 0x3) == 0);795796attribs[i] = (struct agx_attribute) {797.buf = ve.vertex_buffer_index,798.src_offset = ve.src_offset / 4,799.nr_comps_minus_1 = desc->nr_channels - 1,800.format = agx_vertex_format[ve.src_format],801};802}803804return attribs;805}806807static void808agx_bind_vertex_elements_state(struct pipe_context *pctx, void *cso)809{810struct agx_context *ctx = agx_context(pctx);811ctx->attributes = cso;812ctx->dirty |= AGX_DIRTY_VERTEX;813}814815static uint32_t asahi_shader_key_hash(const void *key)816{817return _mesa_hash_data(key, sizeof(struct asahi_shader_key));818}819820static bool asahi_shader_key_equal(const void *a, const void *b)821{822return memcmp(a, b, sizeof(struct asahi_shader_key)) == 0;823}824825static void *826agx_create_shader_state(struct pipe_context *pctx,827const struct pipe_shader_state *cso)828{829struct agx_uncompiled_shader *so = CALLOC_STRUCT(agx_uncompiled_shader);830831if (!so)832return NULL;833834so->base = *cso;835836if (cso->type == PIPE_SHADER_IR_NIR) {837so->nir = cso->ir.nir;838} else {839assert(cso->type == PIPE_SHADER_IR_TGSI);840so->nir = tgsi_to_nir(cso->tokens, pctx->screen, false);841}842843so->variants = _mesa_hash_table_create(NULL, asahi_shader_key_hash, asahi_shader_key_equal);844return so;845}846847static bool848agx_update_shader(struct agx_context *ctx, struct agx_compiled_shader **out,849enum pipe_shader_type stage, struct asahi_shader_key *key)850{851struct agx_uncompiled_shader *so = ctx->stage[stage].shader;852assert(so != NULL);853854struct hash_entry *he = _mesa_hash_table_search(so->variants, key);855856if (he) {857if ((*out) == he->data)858return false;859860*out = he->data;861return true;862}863864struct agx_compiled_shader *compiled = CALLOC_STRUCT(agx_compiled_shader);865struct util_dynarray binary;866util_dynarray_init(&binary, NULL);867868nir_shader *nir = nir_shader_clone(NULL, so->nir);869870if (key->blend.blend_enable) {871nir_lower_blend_options opts = {872.format = { key->rt_formats[0] },873.scalar_blend_const = true874};875876memcpy(opts.rt, key->blend.rt, sizeof(opts.rt));877NIR_PASS_V(nir, nir_lower_blend, opts);878} else if (key->blend.logicop_enable) {879nir_lower_blend_options opts = {880.format = { key->rt_formats[0] },881.logicop_enable = true,882.logicop_func = key->blend.logicop_func,883};884885NIR_PASS_V(nir, nir_lower_blend, opts);886}887888if (stage == PIPE_SHADER_FRAGMENT)889NIR_PASS_V(nir, nir_lower_fragcolor, key->nr_cbufs);890891agx_compile_shader_nir(nir, &key->base, &binary, &compiled->info);892893struct agx_varyings *varyings = &compiled->info.varyings;894unsigned packed_varying_sz = (AGX_VARYING_HEADER_LENGTH + varyings->nr_descs * AGX_VARYING_LENGTH);895uint8_t *packed_varyings = alloca(packed_varying_sz);896897agx_pack(packed_varyings, VARYING_HEADER, cfg) {898cfg.triangle_slots = cfg.point_slots = varyings->nr_slots;899}900901memcpy(packed_varyings + AGX_VARYING_HEADER_LENGTH, varyings->packed,902varyings->nr_descs * AGX_VARYING_LENGTH);903904if (binary.size) {905struct agx_device *dev = agx_device(ctx->base.screen);906compiled->bo = agx_bo_create(dev,907ALIGN_POT(binary.size, 256) + (3 * packed_varying_sz),908AGX_MEMORY_TYPE_SHADER);909memcpy(compiled->bo->ptr.cpu, binary.data, binary.size);910911912/* TODO: Why is the varying descriptor duplicated 3x? */913unsigned offs = ALIGN_POT(binary.size, 256);914for (unsigned copy = 0; copy < 3; ++copy) {915memcpy(((uint8_t *) compiled->bo->ptr.cpu) + offs, packed_varyings, packed_varying_sz);916offs += packed_varying_sz;917}918919compiled->varyings = compiled->bo->ptr.gpu + ALIGN_POT(binary.size, 256);920}921922ralloc_free(nir);923util_dynarray_fini(&binary);924925he = _mesa_hash_table_insert(so->variants, key, compiled);926*out = he->data;927return true;928}929930static bool931agx_update_vs(struct agx_context *ctx)932{933struct agx_vs_shader_key key = {934.num_vbufs = util_last_bit(ctx->vb_mask),935.clip_halfz = ctx->rast->base.clip_halfz,936};937938memcpy(key.attributes, ctx->attributes,939sizeof(key.attributes[0]) * AGX_MAX_ATTRIBS);940941u_foreach_bit(i, ctx->vb_mask) {942assert((ctx->vertex_buffers[i].stride & 0x3) == 0);943key.vbuf_strides[i] = ctx->vertex_buffers[i].stride / 4;944}945946struct asahi_shader_key akey = {947.base.vs = key948};949950return agx_update_shader(ctx, &ctx->vs, PIPE_SHADER_VERTEX, &akey);951}952953static bool954agx_update_fs(struct agx_context *ctx)955{956struct asahi_shader_key key = {957.nr_cbufs = ctx->batch->nr_cbufs,958};959960for (unsigned i = 0; i < key.nr_cbufs; ++i) {961struct pipe_surface *surf = ctx->batch->cbufs[i];962963if (surf) {964enum pipe_format fmt = surf->format;965key.rt_formats[i] = fmt;966key.base.fs.tib_formats[i] = agx_pixel_format[fmt].internal;967} else {968key.rt_formats[i] = PIPE_FORMAT_NONE;969}970}971972memcpy(&key.blend, ctx->blend, sizeof(key.blend));973974return agx_update_shader(ctx, &ctx->fs, PIPE_SHADER_FRAGMENT, &key);975}976977static void978agx_bind_shader_state(struct pipe_context *pctx, void *cso)979{980if (!cso)981return;982983struct agx_context *ctx = agx_context(pctx);984struct agx_uncompiled_shader *so = cso;985986enum pipe_shader_type type = pipe_shader_type_from_mesa(so->nir->info.stage);987ctx->stage[type].shader = so;988}989990static void991agx_delete_compiled_shader(struct hash_entry *ent)992{993struct agx_compiled_shader *so = ent->data;994agx_bo_unreference(so->bo);995FREE(so);996}997998static void999agx_delete_shader_state(struct pipe_context *ctx,1000void *cso)1001{1002struct agx_uncompiled_shader *so = cso;1003_mesa_hash_table_destroy(so->variants, agx_delete_compiled_shader);1004free(so);1005}10061007/* Pipeline consists of a sequence of binding commands followed by a set shader command */1008static uint32_t1009agx_build_pipeline(struct agx_context *ctx, struct agx_compiled_shader *cs, enum pipe_shader_type stage)1010{1011/* Pipelines must be 64-byte aligned */1012struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,1013(16 * AGX_BIND_UNIFORM_LENGTH) + // XXX: correct sizes, break up at compile time1014(ctx->stage[stage].texture_count * AGX_BIND_TEXTURE_LENGTH) +1015(PIPE_MAX_SAMPLERS * AGX_BIND_SAMPLER_LENGTH) +1016AGX_SET_SHADER_EXTENDED_LENGTH + 8,101764);10181019uint8_t *record = ptr.cpu;10201021/* There is a maximum number of half words we may push with a single1022* BIND_UNIFORM record, so split up the range to fit. We only need to call1023* agx_push_location once, however, which reduces the cost. */1024unsigned unif_records = 0;10251026for (unsigned i = 0; i < cs->info.push_ranges; ++i) {1027struct agx_push push = cs->info.push[i];1028uint64_t buffer = agx_push_location(ctx, push, stage);1029unsigned halfs_per_record = 14;1030unsigned records = DIV_ROUND_UP(push.length, halfs_per_record);10311032/* Ensure we don't overflow */1033unif_records += records;1034assert(unif_records < 16);10351036for (unsigned j = 0; j < records; ++j) {1037agx_pack(record, BIND_UNIFORM, cfg) {1038cfg.start_halfs = push.base + (j * halfs_per_record);1039cfg.size_halfs = MIN2(push.length - (j * halfs_per_record), halfs_per_record);1040cfg.buffer = buffer + (j * halfs_per_record * 2);1041}10421043record += AGX_BIND_UNIFORM_LENGTH;1044}1045}10461047for (unsigned i = 0; i < ctx->stage[stage].texture_count; ++i) {1048struct agx_sampler_view *tex = ctx->stage[stage].textures[i];1049agx_batch_add_bo(ctx->batch, tex->desc);1050agx_batch_add_bo(ctx->batch, agx_resource(tex->base.texture)->bo);105110521053agx_pack(record, BIND_TEXTURE, cfg) {1054cfg.start = i;1055cfg.count = 1;1056cfg.buffer = tex->desc->ptr.gpu;1057}10581059record += AGX_BIND_TEXTURE_LENGTH;1060}10611062for (unsigned i = 0; i < PIPE_MAX_SAMPLERS; ++i) {1063struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i];10641065if (!sampler)1066continue;10671068struct agx_bo *bo = sampler->desc;1069agx_batch_add_bo(ctx->batch, bo);10701071agx_pack(record, BIND_SAMPLER, cfg) {1072cfg.start = i;1073cfg.count = 1;1074cfg.buffer = bo->ptr.gpu;1075}10761077record += AGX_BIND_SAMPLER_LENGTH;1078}10791080/* TODO: Can we prepack this? */1081if (stage == PIPE_SHADER_FRAGMENT) {1082agx_pack(record, SET_SHADER_EXTENDED, cfg) {1083cfg.code = cs->bo->ptr.gpu;1084cfg.register_quadwords = 0;1085cfg.unk_3 = 0x8d;1086cfg.unk_1 = 0x2010bd;1087cfg.unk_2 = 0x0d;1088cfg.unk_2b = 1;1089cfg.unk_3b = 0x1;1090cfg.unk_4 = 0x800;1091cfg.preshader_unk = 0xc080;1092cfg.spill_size = 0x2;1093}10941095record += AGX_SET_SHADER_EXTENDED_LENGTH;1096} else {1097agx_pack(record, SET_SHADER, cfg) {1098cfg.code = cs->bo->ptr.gpu;1099cfg.register_quadwords = 0;1100cfg.unk_2b = cs->info.varyings.nr_slots;1101cfg.unk_2 = 0x0d;1102}11031104record += AGX_SET_SHADER_LENGTH;1105}11061107/* End pipeline */1108memset(record, 0, 8);1109assert(ptr.gpu < (1ull << 32));1110return ptr.gpu;1111}11121113/* Internal pipelines (TODO: refactor?) */1114uint64_t1115agx_build_clear_pipeline(struct agx_context *ctx, uint32_t code, uint64_t clear_buf)1116{1117struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,1118(1 * AGX_BIND_UNIFORM_LENGTH) +1119AGX_SET_SHADER_EXTENDED_LENGTH + 8,112064);11211122uint8_t *record = ptr.cpu;11231124agx_pack(record, BIND_UNIFORM, cfg) {1125cfg.start_halfs = (6 * 2);1126cfg.size_halfs = 4;1127cfg.buffer = clear_buf;1128}11291130record += AGX_BIND_UNIFORM_LENGTH;11311132/* TODO: Can we prepack this? */1133agx_pack(record, SET_SHADER_EXTENDED, cfg) {1134cfg.code = code;1135cfg.register_quadwords = 1;1136cfg.unk_3 = 0x8d;1137cfg.unk_2 = 0x0d;1138cfg.unk_2b = 4;1139cfg.frag_unk = 0x880100;1140cfg.preshader_mode = 0; // XXX1141}11421143record += AGX_SET_SHADER_EXTENDED_LENGTH;11441145/* End pipeline */1146memset(record, 0, 8);1147return ptr.gpu;1148}11491150uint64_t1151agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_surface *surf)1152{1153struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,1154(1 * AGX_BIND_TEXTURE_LENGTH) +1155(1 * AGX_BIND_SAMPLER_LENGTH) +1156AGX_SET_SHADER_EXTENDED_LENGTH + 8,115764);11581159uint8_t *record = ptr.cpu;1160struct agx_ptr sampler = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_SAMPLER_LENGTH, 64);1161struct agx_ptr texture = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_TEXTURE_LENGTH, 64);11621163agx_pack(sampler.cpu, SAMPLER, cfg) {1164cfg.magnify_linear = true;1165cfg.minify_linear = false;1166cfg.mip_filter = AGX_MIP_FILTER_NONE;1167cfg.wrap_s = AGX_WRAP_CLAMP_TO_EDGE;1168cfg.wrap_t = AGX_WRAP_CLAMP_TO_EDGE;1169cfg.wrap_r = AGX_WRAP_CLAMP_TO_EDGE;1170cfg.pixel_coordinates = true;1171cfg.compare_func = AGX_COMPARE_FUNC_ALWAYS;1172cfg.unk_2 = 0;1173cfg.unk_3 = 0;1174}11751176agx_pack(texture.cpu, TEXTURE, cfg) {1177struct agx_resource *rsrc = agx_resource(surf->texture);1178const struct util_format_description *desc =1179util_format_description(surf->format);11801181cfg.layout = agx_translate_layout(rsrc->modifier);1182cfg.format = agx_pixel_format[surf->format].hw;1183cfg.swizzle_r = agx_channel_from_pipe(desc->swizzle[0]);1184cfg.swizzle_g = agx_channel_from_pipe(desc->swizzle[1]);1185cfg.swizzle_b = agx_channel_from_pipe(desc->swizzle[2]);1186cfg.swizzle_a = agx_channel_from_pipe(desc->swizzle[3]);1187cfg.width = surf->width;1188cfg.height = surf->height;1189cfg.levels = 1;1190cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);1191cfg.unk_1 = rsrc->bo->ptr.gpu;1192cfg.unk_2 = false;11931194cfg.stride = (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) ?1195(rsrc->slices[0].line_stride - 16) :1196AGX_RT_STRIDE_TILED;1197}11981199agx_pack(record, BIND_TEXTURE, cfg) {1200cfg.start = 0;1201cfg.count = 1;1202cfg.buffer = texture.gpu;1203}12041205record += AGX_BIND_TEXTURE_LENGTH;12061207agx_pack(record, BIND_SAMPLER, cfg) {1208cfg.start = 0;1209cfg.count = 1;1210cfg.buffer = sampler.gpu;1211}12121213record += AGX_BIND_SAMPLER_LENGTH;12141215/* TODO: Can we prepack this? */1216agx_pack(record, SET_SHADER_EXTENDED, cfg) {1217cfg.code = code;1218cfg.register_quadwords = 0;1219cfg.unk_3 = 0x8d;1220cfg.unk_2 = 0x0d;1221cfg.unk_2b = 4;1222cfg.unk_4 = 0;1223cfg.frag_unk = 0x880100;1224cfg.preshader_mode = 0; // XXX1225}12261227record += AGX_SET_SHADER_EXTENDED_LENGTH;12281229/* End pipeline */1230memset(record, 0, 8);1231return ptr.gpu;1232}12331234uint64_t1235agx_build_store_pipeline(struct agx_context *ctx, uint32_t code,1236uint64_t render_target)1237{1238struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,1239(1 * AGX_BIND_TEXTURE_LENGTH) +1240(1 * AGX_BIND_UNIFORM_LENGTH) +1241AGX_SET_SHADER_EXTENDED_LENGTH + 8,124264);12431244uint8_t *record = ptr.cpu;12451246agx_pack(record, BIND_TEXTURE, cfg) {1247cfg.start = 0;1248cfg.count = 1;1249cfg.buffer = render_target;1250}12511252record += AGX_BIND_TEXTURE_LENGTH;12531254uint32_t unk[] = { 0, ~0 };12551256agx_pack(record, BIND_UNIFORM, cfg) {1257cfg.start_halfs = 4;1258cfg.size_halfs = 4;1259cfg.buffer = agx_pool_upload_aligned(&ctx->batch->pool, unk, sizeof(unk), 16);1260}12611262record += AGX_BIND_UNIFORM_LENGTH;12631264/* TODO: Can we prepack this? */1265agx_pack(record, SET_SHADER_EXTENDED, cfg) {1266cfg.code = code;1267cfg.register_quadwords = 1;1268cfg.unk_2 = 0xd;1269cfg.unk_3 = 0x8d;1270cfg.frag_unk = 0x880100;1271cfg.preshader_mode = 0; // XXX1272}12731274record += AGX_SET_SHADER_EXTENDED_LENGTH;12751276/* End pipeline */1277memset(record, 0, 8);1278return ptr.gpu;1279}12801281static uint64_t1282demo_launch_fragment(struct agx_context *ctx, struct agx_pool *pool, uint32_t pipeline, uint32_t varyings, unsigned input_count)1283{1284struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_BIND_PIPELINE_LENGTH, 64);12851286agx_pack(t.cpu, BIND_PIPELINE, cfg) {1287cfg.tag = AGX_BIND_PIPELINE_FRAGMENT;1288cfg.sampler_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;1289cfg.texture_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;1290cfg.input_count = input_count;1291cfg.pipeline = pipeline;1292cfg.fs_varyings = varyings;1293};12941295return t.gpu;1296}12971298static uint64_t1299demo_interpolation(struct agx_compiled_shader *fs, struct agx_pool *pool)1300{1301struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_INTERPOLATION_LENGTH, 64);13021303agx_pack(t.cpu, INTERPOLATION, cfg) {1304cfg.varying_count = fs->info.varyings.nr_slots;1305};13061307return t.gpu;1308}13091310static uint64_t1311demo_linkage(struct agx_compiled_shader *vs, struct agx_pool *pool)1312{1313struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_LINKAGE_LENGTH, 64);13141315agx_pack(t.cpu, LINKAGE, cfg) {1316cfg.varying_count = vs->info.varyings.nr_slots;13171318// 0x2 for fragcoordz, 0x1 for varyings at all1319cfg.unk_1 = 0x210000 | (vs->info.writes_psiz ? 0x40000 : 0);1320};13211322return t.gpu;1323}13241325static uint64_t1326demo_rasterizer(struct agx_context *ctx, struct agx_pool *pool, bool is_points)1327{1328struct agx_rasterizer *rast = ctx->rast;1329struct agx_rasterizer_packed out;13301331agx_pack(&out, RASTERIZER, cfg) {1332bool back_stencil = ctx->zs.base.stencil[1].enabled;1333cfg.front.stencil_reference = ctx->stencil_ref.ref_value[0];1334cfg.back.stencil_reference = back_stencil ?1335ctx->stencil_ref.ref_value[1] :1336cfg.front.stencil_reference;13371338cfg.front.line_width = cfg.back.line_width = rast->line_width;1339cfg.front.polygon_mode = cfg.back.polygon_mode = AGX_POLYGON_MODE_FILL;13401341cfg.unk_fill_lines = is_points; /* XXX: what is this? */13421343/* Always enable scissoring so we may scissor to the viewport (TODO:1344* optimize this out if the viewport is the default and the app does not1345* use the scissor test) */1346cfg.scissor_enable = true;1347};13481349/* Words 2-3: front */1350out.opaque[2] |= ctx->zs.front.opaque[0];1351out.opaque[3] |= ctx->zs.front.opaque[1];13521353/* Words 4-5: back */1354out.opaque[4] |= ctx->zs.back.opaque[0];1355out.opaque[5] |= ctx->zs.back.opaque[1];13561357return agx_pool_upload_aligned(pool, &out, sizeof(out), 64);1358}13591360static uint64_t1361demo_unk11(struct agx_pool *pool, bool prim_lines, bool prim_points, bool reads_tib)1362{1363#define UNK11_FILL_MODE_LINES_1 (1 << 26)13641365#define UNK11_FILL_MODE_LINES_2 (0x5004 << 16)1366#define UNK11_LINES (0x10000000)1367#define UNK11_POINTS (0x40000000)13681369#define UNK11_READS_TIB (0x20000000)13701371uint32_t unk[] = {13720x200004a,13730x200 | ((prim_lines || prim_points) ? UNK11_FILL_MODE_LINES_1 : 0) | (reads_tib ? UNK11_READS_TIB : 0),13740x7e00000 | (prim_lines ? UNK11_LINES : 0) | (prim_points ? UNK11_POINTS : 0),13750x7e00000 | (prim_lines ? UNK11_LINES : 0) | (prim_points ? UNK11_POINTS : 0),137613770x1ffff1378};13791380return agx_pool_upload(pool, unk, sizeof(unk));1381}13821383static uint64_t1384demo_unk12(struct agx_pool *pool)1385{1386uint32_t unk[] = {13870x410000,13880x1e3ce508,13890xa01390};13911392return agx_pool_upload(pool, unk, sizeof(unk));1393}13941395static uint64_t1396agx_set_scissor_index(struct agx_pool *pool, unsigned index)1397{1398struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_SET_SCISSOR_LENGTH, 64);13991400agx_pack(T.cpu, SET_SCISSOR, cfg) {1401cfg.index = index;1402};14031404return T.gpu;1405}14061407static void1408agx_push_record(uint8_t **out, unsigned size_words, uint64_t ptr)1409{1410assert(ptr < (1ull << 40));1411assert(size_words < (1ull << 24));14121413uint64_t value = (size_words | (ptr << 24));1414memcpy(*out, &value, sizeof(value));1415*out += sizeof(value);1416}14171418static uint8_t *1419agx_encode_state(struct agx_context *ctx, uint8_t *out,1420uint32_t pipeline_vertex, uint32_t pipeline_fragment, uint32_t varyings,1421bool is_lines, bool is_points)1422{1423agx_pack(out, BIND_PIPELINE, cfg) {1424cfg.tag = AGX_BIND_PIPELINE_VERTEX;1425cfg.pipeline = pipeline_vertex;1426cfg.vs_output_count_1 = ctx->vs->info.varyings.nr_slots;1427cfg.vs_output_count_2 = ctx->vs->info.varyings.nr_slots;1428cfg.sampler_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;1429cfg.texture_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;1430}14311432/* yes, it's really 17 bytes */1433out += AGX_BIND_PIPELINE_LENGTH;1434*(out++) = 0x0;14351436struct agx_pool *pool = &ctx->batch->pool;1437struct agx_ptr zero = agx_pool_alloc_aligned(pool, 16, 256);1438memset(zero.cpu, 0, 16);14391440bool reads_tib = ctx->fs->info.reads_tib;14411442agx_push_record(&out, 0, zero.gpu);1443agx_push_record(&out, 5, demo_interpolation(ctx->fs, pool));1444agx_push_record(&out, 5, demo_launch_fragment(ctx, pool, pipeline_fragment, varyings, ctx->fs->info.varyings.nr_descs));1445agx_push_record(&out, 4, demo_linkage(ctx->vs, pool));1446agx_push_record(&out, 7, demo_rasterizer(ctx, pool, is_points));1447agx_push_record(&out, 5, demo_unk11(pool, is_lines, is_points, reads_tib));14481449if (ctx->dirty & (AGX_DIRTY_VIEWPORT | AGX_DIRTY_SCISSOR)) {1450struct agx_viewport_scissor vps = agx_upload_viewport_scissor(pool,1451ctx->batch, &ctx->viewport,1452ctx->rast->base.scissor ? &ctx->scissor : NULL);14531454agx_push_record(&out, 10, vps.viewport);1455agx_push_record(&out, 2, agx_set_scissor_index(pool, vps.scissor));1456}14571458agx_push_record(&out, 3, demo_unk12(pool));1459agx_push_record(&out, 2, agx_pool_upload(pool, ctx->rast->cull, sizeof(ctx->rast->cull)));14601461return (out - 1); // XXX: alignment fixup, or something1462}14631464static enum agx_primitive1465agx_primitive_for_pipe(enum pipe_prim_type mode)1466{1467switch (mode) {1468case PIPE_PRIM_POINTS: return AGX_PRIMITIVE_POINTS;1469case PIPE_PRIM_LINES: return AGX_PRIMITIVE_LINES;1470case PIPE_PRIM_LINE_STRIP: return AGX_PRIMITIVE_LINE_STRIP;1471case PIPE_PRIM_LINE_LOOP: return AGX_PRIMITIVE_LINE_LOOP;1472case PIPE_PRIM_TRIANGLES: return AGX_PRIMITIVE_TRIANGLES;1473case PIPE_PRIM_TRIANGLE_STRIP: return AGX_PRIMITIVE_TRIANGLE_STRIP;1474case PIPE_PRIM_TRIANGLE_FAN: return AGX_PRIMITIVE_TRIANGLE_FAN;1475case PIPE_PRIM_QUADS: return AGX_PRIMITIVE_QUADS;1476case PIPE_PRIM_QUAD_STRIP: return AGX_PRIMITIVE_QUAD_STRIP;1477default: unreachable("todo: other primitive types");1478}1479}14801481static uint64_t1482agx_index_buffer_ptr(struct agx_batch *batch,1483const struct pipe_draw_start_count_bias *draw,1484const struct pipe_draw_info *info)1485{1486off_t offset = draw->start * info->index_size;14871488if (!info->has_user_indices) {1489struct agx_bo *bo = agx_resource(info->index.resource)->bo;1490agx_batch_add_bo(batch, bo);14911492return bo->ptr.gpu + offset;1493} else {1494return agx_pool_upload_aligned(&batch->pool,1495((uint8_t *) info->index.user) + offset,1496draw->count * info->index_size, 64);1497}1498}14991500static bool1501agx_scissor_culls_everything(struct agx_context *ctx)1502{1503const struct pipe_scissor_state ss = ctx->scissor;15041505return ctx->rast->base.scissor &&1506((ss.minx == ss.maxx) || (ss.miny == ss.maxy));1507}15081509static void1510agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,1511unsigned drawid_offset,1512const struct pipe_draw_indirect_info *indirect,1513const struct pipe_draw_start_count_bias *draws,1514unsigned num_draws)1515{1516if (num_draws > 1) {1517util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);1518return;1519}15201521if (info->index_size && draws->index_bias)1522unreachable("todo: index bias");1523if (info->instance_count != 1)1524unreachable("todo: instancing");15251526struct agx_context *ctx = agx_context(pctx);1527struct agx_batch *batch = ctx->batch;15281529if (agx_scissor_culls_everything(ctx))1530return;15311532/* TODO: masks */1533ctx->batch->draw |= ~0;15341535/* TODO: Dirty track */1536agx_update_vs(ctx);1537agx_update_fs(ctx);15381539agx_batch_add_bo(batch, ctx->vs->bo);1540agx_batch_add_bo(batch, ctx->fs->bo);15411542bool is_lines =1543(info->mode == PIPE_PRIM_LINES) ||1544(info->mode == PIPE_PRIM_LINE_STRIP) ||1545(info->mode == PIPE_PRIM_LINE_LOOP);15461547uint8_t *out = agx_encode_state(ctx, batch->encoder_current,1548agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX),1549agx_build_pipeline(ctx, ctx->fs, PIPE_SHADER_FRAGMENT),1550ctx->fs->varyings, is_lines, info->mode == PIPE_PRIM_POINTS);15511552enum agx_primitive prim = agx_primitive_for_pipe(info->mode);1553unsigned idx_size = info->index_size;15541555if (idx_size) {1556uint64_t ib = agx_index_buffer_ptr(batch, draws, info);15571558/* Index sizes are encoded logarithmically */1559STATIC_ASSERT(__builtin_ctz(1) == AGX_INDEX_SIZE_U8);1560STATIC_ASSERT(__builtin_ctz(2) == AGX_INDEX_SIZE_U16);1561STATIC_ASSERT(__builtin_ctz(4) == AGX_INDEX_SIZE_U32);1562assert((idx_size == 1) || (idx_size == 2) || (idx_size == 4));15631564agx_pack(out, INDEXED_DRAW, cfg) {1565cfg.restart_index = info->restart_index;1566cfg.unk_2a = (ib >> 32);1567cfg.primitive = prim;1568cfg.restart_enable = info->primitive_restart;1569cfg.index_size = __builtin_ctz(idx_size);1570cfg.index_buffer_offset = (ib & BITFIELD_MASK(32));1571cfg.index_buffer_size = ALIGN_POT(draws->count * idx_size, 4);1572cfg.index_count = draws->count;1573cfg.instance_count = info->instance_count;1574cfg.base_vertex = draws->index_bias;1575};15761577out += AGX_INDEXED_DRAW_LENGTH;1578} else {1579agx_pack(out, DRAW, cfg) {1580cfg.primitive = prim;1581cfg.vertex_start = draws->start;1582cfg.vertex_count = draws->count;1583cfg.instance_count = info->instance_count;1584};15851586out += AGX_DRAW_LENGTH;1587}15881589batch->encoder_current = out;1590ctx->dirty = 0;1591}15921593void agx_init_state_functions(struct pipe_context *ctx);15941595void1596agx_init_state_functions(struct pipe_context *ctx)1597{1598ctx->create_blend_state = agx_create_blend_state;1599ctx->create_depth_stencil_alpha_state = agx_create_zsa_state;1600ctx->create_fs_state = agx_create_shader_state;1601ctx->create_rasterizer_state = agx_create_rs_state;1602ctx->create_sampler_state = agx_create_sampler_state;1603ctx->create_sampler_view = agx_create_sampler_view;1604ctx->create_surface = agx_create_surface;1605ctx->create_vertex_elements_state = agx_create_vertex_elements;1606ctx->create_vs_state = agx_create_shader_state;1607ctx->bind_blend_state = agx_bind_blend_state;1608ctx->bind_depth_stencil_alpha_state = agx_bind_zsa_state;1609ctx->bind_sampler_states = agx_bind_sampler_states;1610ctx->bind_fs_state = agx_bind_shader_state;1611ctx->bind_rasterizer_state = agx_bind_rasterizer_state;1612ctx->bind_vertex_elements_state = agx_bind_vertex_elements_state;1613ctx->bind_vs_state = agx_bind_shader_state;1614ctx->delete_blend_state = agx_delete_state;1615ctx->delete_depth_stencil_alpha_state = agx_delete_state;1616ctx->delete_fs_state = agx_delete_shader_state;1617ctx->delete_rasterizer_state = agx_delete_state;1618ctx->delete_sampler_state = agx_delete_sampler_state;1619ctx->delete_vertex_elements_state = agx_delete_state;1620ctx->delete_vs_state = agx_delete_state;1621ctx->set_blend_color = agx_set_blend_color;1622ctx->set_clip_state = agx_set_clip_state;1623ctx->set_constant_buffer = agx_set_constant_buffer;1624ctx->set_sampler_views = agx_set_sampler_views;1625ctx->set_framebuffer_state = agx_set_framebuffer_state;1626ctx->set_polygon_stipple = agx_set_polygon_stipple;1627ctx->set_sample_mask = agx_set_sample_mask;1628ctx->set_scissor_states = agx_set_scissor_states;1629ctx->set_stencil_ref = agx_set_stencil_ref;1630ctx->set_vertex_buffers = agx_set_vertex_buffers;1631ctx->set_viewport_states = agx_set_viewport_states;1632ctx->sampler_view_destroy = agx_sampler_view_destroy;1633ctx->surface_destroy = agx_surface_destroy;1634ctx->draw_vbo = agx_draw_vbo;1635ctx->create_stream_output_target = agx_create_stream_output_target;1636ctx->stream_output_target_destroy = agx_stream_output_target_destroy;1637ctx->set_stream_output_targets = agx_set_stream_output_targets;1638}163916401641