Path: blob/21.2-virgl/src/gallium/drivers/freedreno/a3xx/fd3_program.c
4574 views
/*1* Copyright (C) 2013 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "pipe/p_state.h"27#include "util/format/u_format.h"28#include "util/u_inlines.h"29#include "util/u_math.h"30#include "util/u_memory.h"31#include "util/u_string.h"3233#include "freedreno_program.h"3435#include "fd3_emit.h"36#include "fd3_format.h"37#include "fd3_program.h"38#include "fd3_texture.h"3940bool41fd3_needs_manual_clipping(const struct ir3_shader *shader,42const struct pipe_rasterizer_state *rast)43{44uint64_t outputs = ir3_shader_outputs(shader);4546return (!rast->depth_clip_near ||47util_bitcount(rast->clip_plane_enable) > 6 ||48outputs & ((1ULL << VARYING_SLOT_CLIP_VERTEX) |49(1ULL << VARYING_SLOT_CLIP_DIST0) |50(1ULL << VARYING_SLOT_CLIP_DIST1)));51}5253static void54emit_shader(struct fd_ringbuffer *ring, const struct ir3_shader_variant *so)55{56const struct ir3_info *si = &so->info;57enum adreno_state_block sb;58enum adreno_state_src src;59uint32_t i, sz, *bin;6061if (so->type == MESA_SHADER_VERTEX) {62sb = SB_VERT_SHADER;63} else {64sb = SB_FRAG_SHADER;65}6667if (FD_DBG(DIRECT)) {68sz = si->sizedwords;69src = SS_DIRECT;70bin = fd_bo_map(so->bo);71} else {72sz = 0;73src = SS_INDIRECT;74bin = NULL;75}7677OUT_PKT3(ring, CP_LOAD_STATE, 2 + sz);78OUT_RING(ring, CP_LOAD_STATE_0_DST_OFF(0) | CP_LOAD_STATE_0_STATE_SRC(src) |79CP_LOAD_STATE_0_STATE_BLOCK(sb) |80CP_LOAD_STATE_0_NUM_UNIT(so->instrlen));81if (bin) {82OUT_RING(ring, CP_LOAD_STATE_1_EXT_SRC_ADDR(0) |83CP_LOAD_STATE_1_STATE_TYPE(ST_SHADER));84} else {85OUT_RELOC(ring, so->bo, 0, CP_LOAD_STATE_1_STATE_TYPE(ST_SHADER), 0);86}87for (i = 0; i < sz; i++) {88OUT_RING(ring, bin[i]);89}90}9192void93fd3_program_emit(struct fd_ringbuffer *ring, struct fd3_emit *emit, int nr,94struct pipe_surface **bufs)95{96const struct ir3_shader_variant *vp, *fp;97const struct ir3_info *vsi, *fsi;98enum a3xx_instrbuffermode fpbuffer, vpbuffer;99uint32_t fpbuffersz, vpbuffersz, fsoff;100uint32_t pos_regid, posz_regid, psize_regid;101uint32_t ij_regid[4], face_regid, coord_regid, zwcoord_regid;102uint32_t color_regid[4] = {0};103int constmode;104int i, j;105106debug_assert(nr <= ARRAY_SIZE(color_regid));107108vp = fd3_emit_get_vp(emit);109fp = fd3_emit_get_fp(emit);110111vsi = &vp->info;112fsi = &fp->info;113114fpbuffer = BUFFER;115vpbuffer = BUFFER;116fpbuffersz = fp->instrlen;117vpbuffersz = vp->instrlen;118119/*120* Decide whether to use BUFFER or CACHE mode for VS and FS. It121* appears like 256 is the hard limit, but when the combined size122* exceeds 128 then blob will try to keep FS in BUFFER mode and123* switch to CACHE for VS until VS is too large. The blob seems124* to switch FS out of BUFFER mode at slightly under 128. But125* a bit fuzzy on the decision tree, so use slightly conservative126* limits.127*128* TODO check if these thresholds for BUFFER vs CACHE mode are the129* same for all a3xx or whether we need to consider the gpuid130*/131132if ((fpbuffersz + vpbuffersz) > 128) {133if (fpbuffersz < 112) {134/* FP:BUFFER VP:CACHE */135vpbuffer = CACHE;136vpbuffersz = 256 - fpbuffersz;137} else if (vpbuffersz < 112) {138/* FP:CACHE VP:BUFFER */139fpbuffer = CACHE;140fpbuffersz = 256 - vpbuffersz;141} else {142/* FP:CACHE VP:CACHE */143vpbuffer = fpbuffer = CACHE;144vpbuffersz = fpbuffersz = 192;145}146}147148if (fpbuffer == BUFFER) {149fsoff = 128 - fpbuffersz;150} else {151fsoff = 256 - fpbuffersz;152}153154/* seems like vs->constlen + fs->constlen > 256, then CONSTMODE=1 */155constmode = ((vp->constlen + fp->constlen) > 256) ? 1 : 0;156157pos_regid = ir3_find_output_regid(vp, VARYING_SLOT_POS);158posz_regid = ir3_find_output_regid(fp, FRAG_RESULT_DEPTH);159psize_regid = ir3_find_output_regid(vp, VARYING_SLOT_PSIZ);160if (fp->color0_mrt) {161color_regid[0] = color_regid[1] = color_regid[2] = color_regid[3] =162ir3_find_output_regid(fp, FRAG_RESULT_COLOR);163} else {164color_regid[0] = ir3_find_output_regid(fp, FRAG_RESULT_DATA0);165color_regid[1] = ir3_find_output_regid(fp, FRAG_RESULT_DATA1);166color_regid[2] = ir3_find_output_regid(fp, FRAG_RESULT_DATA2);167color_regid[3] = ir3_find_output_regid(fp, FRAG_RESULT_DATA3);168}169170face_regid = ir3_find_sysval_regid(fp, SYSTEM_VALUE_FRONT_FACE);171coord_regid = ir3_find_sysval_regid(fp, SYSTEM_VALUE_FRAG_COORD);172zwcoord_regid =173(coord_regid == regid(63, 0)) ? regid(63, 0) : (coord_regid + 2);174ij_regid[0] =175ir3_find_sysval_regid(fp, SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL);176ij_regid[1] =177ir3_find_sysval_regid(fp, SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL);178ij_regid[2] =179ir3_find_sysval_regid(fp, SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID);180ij_regid[3] =181ir3_find_sysval_regid(fp, SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID);182183/* adjust regids for alpha output formats. there is no alpha render184* format, so it's just treated like red185*/186for (i = 0; i < nr; i++)187if (util_format_is_alpha(pipe_surface_format(bufs[i])))188color_regid[i] += 3;189190/* we could probably divide this up into things that need to be191* emitted if frag-prog is dirty vs if vert-prog is dirty..192*/193194OUT_PKT0(ring, REG_A3XX_HLSQ_CONTROL_0_REG, 6);195OUT_RING(ring, A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE(FOUR_QUADS) |196A3XX_HLSQ_CONTROL_0_REG_FSSUPERTHREADENABLE |197A3XX_HLSQ_CONTROL_0_REG_CONSTMODE(constmode) |198/* NOTE: I guess SHADERRESTART and CONSTFULLUPDATE maybe199* flush some caches? I think we only need to set those200* bits if we have updated const or shader..201*/202A3XX_HLSQ_CONTROL_0_REG_SPSHADERRESTART |203A3XX_HLSQ_CONTROL_0_REG_SPCONSTFULLUPDATE);204OUT_RING(ring, A3XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE(TWO_QUADS) |205A3XX_HLSQ_CONTROL_1_REG_VSSUPERTHREADENABLE |206A3XX_HLSQ_CONTROL_1_REG_FRAGCOORDXYREGID(coord_regid) |207A3XX_HLSQ_CONTROL_1_REG_FRAGCOORDZWREGID(zwcoord_regid));208OUT_RING(ring, A3XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD(31) |209A3XX_HLSQ_CONTROL_2_REG_FACENESSREGID(face_regid));210OUT_RING(ring,211A3XX_HLSQ_CONTROL_3_REG_IJPERSPCENTERREGID(ij_regid[0]) |212A3XX_HLSQ_CONTROL_3_REG_IJNONPERSPCENTERREGID(ij_regid[1]) |213A3XX_HLSQ_CONTROL_3_REG_IJPERSPCENTROIDREGID(ij_regid[2]) |214A3XX_HLSQ_CONTROL_3_REG_IJNONPERSPCENTROIDREGID(ij_regid[3]));215OUT_RING(ring, A3XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH(vp->constlen) |216A3XX_HLSQ_VS_CONTROL_REG_CONSTSTARTOFFSET(0) |217A3XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH(vpbuffersz));218OUT_RING(ring, A3XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH(fp->constlen) |219A3XX_HLSQ_FS_CONTROL_REG_CONSTSTARTOFFSET(128) |220A3XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH(fpbuffersz));221222OUT_PKT0(ring, REG_A3XX_SP_SP_CTRL_REG, 1);223OUT_RING(ring, A3XX_SP_SP_CTRL_REG_CONSTMODE(constmode) |224COND(emit->binning_pass, A3XX_SP_SP_CTRL_REG_BINNING) |225A3XX_SP_SP_CTRL_REG_SLEEPMODE(1) |226A3XX_SP_SP_CTRL_REG_L0MODE(0));227228OUT_PKT0(ring, REG_A3XX_SP_VS_LENGTH_REG, 1);229OUT_RING(ring, A3XX_SP_VS_LENGTH_REG_SHADERLENGTH(vp->instrlen));230231OUT_PKT0(ring, REG_A3XX_SP_VS_CTRL_REG0, 3);232OUT_RING(ring,233A3XX_SP_VS_CTRL_REG0_THREADMODE(MULTI) |234A3XX_SP_VS_CTRL_REG0_INSTRBUFFERMODE(vpbuffer) |235COND(vpbuffer == CACHE, A3XX_SP_VS_CTRL_REG0_CACHEINVALID) |236A3XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(vsi->max_half_reg + 1) |237A3XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(vsi->max_reg + 1) |238A3XX_SP_VS_CTRL_REG0_THREADSIZE(TWO_QUADS) |239A3XX_SP_VS_CTRL_REG0_SUPERTHREADMODE |240A3XX_SP_VS_CTRL_REG0_LENGTH(vpbuffersz));241OUT_RING(ring,242A3XX_SP_VS_CTRL_REG1_CONSTLENGTH(vp->constlen) |243A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING(vp->total_in) |244A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT(MAX2(vp->constlen - 1, 0)));245OUT_RING(ring, A3XX_SP_VS_PARAM_REG_POSREGID(pos_regid) |246A3XX_SP_VS_PARAM_REG_PSIZEREGID(psize_regid) |247A3XX_SP_VS_PARAM_REG_TOTALVSOUTVAR(fp->varying_in));248249struct ir3_shader_linkage l = {0};250ir3_link_shaders(&l, vp, fp, false);251252for (i = 0, j = 0; (i < 16) && (j < l.cnt); i++) {253uint32_t reg = 0;254255OUT_PKT0(ring, REG_A3XX_SP_VS_OUT_REG(i), 1);256257reg |= A3XX_SP_VS_OUT_REG_A_REGID(l.var[j].regid);258reg |= A3XX_SP_VS_OUT_REG_A_COMPMASK(l.var[j].compmask);259j++;260261reg |= A3XX_SP_VS_OUT_REG_B_REGID(l.var[j].regid);262reg |= A3XX_SP_VS_OUT_REG_B_COMPMASK(l.var[j].compmask);263j++;264265OUT_RING(ring, reg);266}267268for (i = 0, j = 0; (i < 8) && (j < l.cnt); i++) {269uint32_t reg = 0;270271OUT_PKT0(ring, REG_A3XX_SP_VS_VPC_DST_REG(i), 1);272273reg |= A3XX_SP_VS_VPC_DST_REG_OUTLOC0(l.var[j++].loc + 8);274reg |= A3XX_SP_VS_VPC_DST_REG_OUTLOC1(l.var[j++].loc + 8);275reg |= A3XX_SP_VS_VPC_DST_REG_OUTLOC2(l.var[j++].loc + 8);276reg |= A3XX_SP_VS_VPC_DST_REG_OUTLOC3(l.var[j++].loc + 8);277278OUT_RING(ring, reg);279}280281OUT_PKT0(ring, REG_A3XX_SP_VS_OBJ_OFFSET_REG, 2);282OUT_RING(ring, A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(0) |283A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(0));284OUT_RELOC(ring, vp->bo, 0, 0, 0); /* SP_VS_OBJ_START_REG */285286if (emit->binning_pass) {287OUT_PKT0(ring, REG_A3XX_SP_FS_LENGTH_REG, 1);288OUT_RING(ring, 0x00000000);289290OUT_PKT0(ring, REG_A3XX_SP_FS_CTRL_REG0, 2);291OUT_RING(ring, A3XX_SP_FS_CTRL_REG0_THREADMODE(MULTI) |292A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE(BUFFER));293OUT_RING(ring, 0x00000000);294295OUT_PKT0(ring, REG_A3XX_SP_FS_OBJ_OFFSET_REG, 1);296OUT_RING(ring, A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(128) |297A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(0));298} else {299OUT_PKT0(ring, REG_A3XX_SP_FS_LENGTH_REG, 1);300OUT_RING(ring, A3XX_SP_FS_LENGTH_REG_SHADERLENGTH(fp->instrlen));301302OUT_PKT0(ring, REG_A3XX_SP_FS_CTRL_REG0, 2);303OUT_RING(ring,304A3XX_SP_FS_CTRL_REG0_THREADMODE(MULTI) |305A3XX_SP_FS_CTRL_REG0_INSTRBUFFERMODE(fpbuffer) |306COND(fpbuffer == CACHE, A3XX_SP_FS_CTRL_REG0_CACHEINVALID) |307A3XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(fsi->max_half_reg + 1) |308A3XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(fsi->max_reg + 1) |309A3XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP |310A3XX_SP_FS_CTRL_REG0_THREADSIZE(FOUR_QUADS) |311A3XX_SP_FS_CTRL_REG0_SUPERTHREADMODE |312COND(fp->need_pixlod, A3XX_SP_FS_CTRL_REG0_PIXLODENABLE) |313A3XX_SP_FS_CTRL_REG0_LENGTH(fpbuffersz));314OUT_RING(ring, A3XX_SP_FS_CTRL_REG1_CONSTLENGTH(fp->constlen) |315A3XX_SP_FS_CTRL_REG1_INITIALOUTSTANDING(fp->sysval_in) |316A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT(317MAX2(fp->constlen - 1, 0)) |318A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET(63));319320OUT_PKT0(ring, REG_A3XX_SP_FS_OBJ_OFFSET_REG, 2);321OUT_RING(ring, A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(322MAX2(128, vp->constlen)) |323A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(fsoff));324OUT_RELOC(ring, fp->bo, 0, 0, 0); /* SP_FS_OBJ_START_REG */325}326327OUT_PKT0(ring, REG_A3XX_SP_FS_OUTPUT_REG, 1);328OUT_RING(ring, COND(fp->writes_pos, A3XX_SP_FS_OUTPUT_REG_DEPTH_ENABLE) |329A3XX_SP_FS_OUTPUT_REG_DEPTH_REGID(posz_regid) |330A3XX_SP_FS_OUTPUT_REG_MRT(MAX2(1, nr) - 1));331332OUT_PKT0(ring, REG_A3XX_SP_FS_MRT_REG(0), 4);333for (i = 0; i < 4; i++) {334uint32_t mrt_reg =335A3XX_SP_FS_MRT_REG_REGID(color_regid[i]) |336COND(color_regid[i] & HALF_REG_ID, A3XX_SP_FS_MRT_REG_HALF_PRECISION);337338if (i < nr) {339enum pipe_format fmt = pipe_surface_format(bufs[i]);340mrt_reg |=341COND(util_format_is_pure_uint(fmt), A3XX_SP_FS_MRT_REG_UINT) |342COND(util_format_is_pure_sint(fmt), A3XX_SP_FS_MRT_REG_SINT);343}344OUT_RING(ring, mrt_reg);345}346347if (emit->binning_pass) {348OUT_PKT0(ring, REG_A3XX_VPC_ATTR, 2);349OUT_RING(ring, A3XX_VPC_ATTR_THRDASSIGN(1) | A3XX_VPC_ATTR_LMSIZE(1) |350COND(vp->writes_psize, A3XX_VPC_ATTR_PSIZE));351OUT_RING(ring, 0x00000000);352} else {353uint32_t vinterp[4], flatshade[2], vpsrepl[4];354355memset(vinterp, 0, sizeof(vinterp));356memset(flatshade, 0, sizeof(flatshade));357memset(vpsrepl, 0, sizeof(vpsrepl));358359/* figure out VARYING_INTERP / FLAT_SHAD register values: */360for (j = -1; (j = ir3_next_varying(fp, j)) < (int)fp->inputs_count;) {361/* NOTE: varyings are packed, so if compmask is 0xb362* then first, third, and fourth component occupy363* three consecutive varying slots:364*/365unsigned compmask = fp->inputs[j].compmask;366367uint32_t inloc = fp->inputs[j].inloc;368369if (fp->inputs[j].flat ||370(fp->inputs[j].rasterflat && emit->rasterflat)) {371uint32_t loc = inloc;372373for (i = 0; i < 4; i++) {374if (compmask & (1 << i)) {375vinterp[loc / 16] |= FLAT << ((loc % 16) * 2);376flatshade[loc / 32] |= 1 << (loc % 32);377loc++;378}379}380}381382bool coord_mode = emit->sprite_coord_mode;383if (ir3_point_sprite(fp, j, emit->sprite_coord_enable, &coord_mode)) {384/* mask is two 2-bit fields, where:385* '01' -> S386* '10' -> T387* '11' -> 1 - T (flip mode)388*/389unsigned mask = coord_mode ? 0b1101 : 0b1001;390uint32_t loc = inloc;391if (compmask & 0x1) {392vpsrepl[loc / 16] |= ((mask >> 0) & 0x3) << ((loc % 16) * 2);393loc++;394}395if (compmask & 0x2) {396vpsrepl[loc / 16] |= ((mask >> 2) & 0x3) << ((loc % 16) * 2);397loc++;398}399if (compmask & 0x4) {400/* .z <- 0.0f */401vinterp[loc / 16] |= 0b10 << ((loc % 16) * 2);402loc++;403}404if (compmask & 0x8) {405/* .w <- 1.0f */406vinterp[loc / 16] |= 0b11 << ((loc % 16) * 2);407loc++;408}409}410}411412OUT_PKT0(ring, REG_A3XX_VPC_ATTR, 2);413OUT_RING(ring, A3XX_VPC_ATTR_TOTALATTR(fp->total_in) |414A3XX_VPC_ATTR_THRDASSIGN(1) | A3XX_VPC_ATTR_LMSIZE(1) |415COND(vp->writes_psize, A3XX_VPC_ATTR_PSIZE));416OUT_RING(ring, A3XX_VPC_PACK_NUMFPNONPOSVAR(fp->total_in) |417A3XX_VPC_PACK_NUMNONPOSVSVAR(fp->total_in));418419OUT_PKT0(ring, REG_A3XX_VPC_VARYING_INTERP_MODE(0), 4);420OUT_RING(ring, vinterp[0]); /* VPC_VARYING_INTERP[0].MODE */421OUT_RING(ring, vinterp[1]); /* VPC_VARYING_INTERP[1].MODE */422OUT_RING(ring, vinterp[2]); /* VPC_VARYING_INTERP[2].MODE */423OUT_RING(ring, vinterp[3]); /* VPC_VARYING_INTERP[3].MODE */424425OUT_PKT0(ring, REG_A3XX_VPC_VARYING_PS_REPL_MODE(0), 4);426OUT_RING(ring, vpsrepl[0]); /* VPC_VARYING_PS_REPL[0].MODE */427OUT_RING(ring, vpsrepl[1]); /* VPC_VARYING_PS_REPL[1].MODE */428OUT_RING(ring, vpsrepl[2]); /* VPC_VARYING_PS_REPL[2].MODE */429OUT_RING(ring, vpsrepl[3]); /* VPC_VARYING_PS_REPL[3].MODE */430431OUT_PKT0(ring, REG_A3XX_SP_FS_FLAT_SHAD_MODE_REG_0, 2);432OUT_RING(ring, flatshade[0]); /* SP_FS_FLAT_SHAD_MODE_REG_0 */433OUT_RING(ring, flatshade[1]); /* SP_FS_FLAT_SHAD_MODE_REG_1 */434}435436if (vpbuffer == BUFFER)437emit_shader(ring, vp);438439OUT_PKT0(ring, REG_A3XX_VFD_PERFCOUNTER0_SELECT, 1);440OUT_RING(ring, 0x00000000); /* VFD_PERFCOUNTER0_SELECT */441442if (!emit->binning_pass) {443if (fpbuffer == BUFFER)444emit_shader(ring, fp);445446OUT_PKT0(ring, REG_A3XX_VFD_PERFCOUNTER0_SELECT, 1);447OUT_RING(ring, 0x00000000); /* VFD_PERFCOUNTER0_SELECT */448}449}450451static struct ir3_program_state *452fd3_program_create(void *data, struct ir3_shader_variant *bs,453struct ir3_shader_variant *vs, struct ir3_shader_variant *hs,454struct ir3_shader_variant *ds, struct ir3_shader_variant *gs,455struct ir3_shader_variant *fs,456const struct ir3_shader_key *key) in_dt457{458struct fd_context *ctx = fd_context(data);459struct fd3_program_state *state = CALLOC_STRUCT(fd3_program_state);460461tc_assert_driver_thread(ctx->tc);462463state->bs = bs;464state->vs = vs;465state->fs = fs;466467return &state->base;468}469470static void471fd3_program_destroy(void *data, struct ir3_program_state *state)472{473struct fd3_program_state *so = fd3_program_state(state);474free(so);475}476477static const struct ir3_cache_funcs cache_funcs = {478.create_state = fd3_program_create,479.destroy_state = fd3_program_destroy,480};481482void483fd3_prog_init(struct pipe_context *pctx)484{485struct fd_context *ctx = fd_context(pctx);486487ctx->shader_cache = ir3_cache_create(&cache_funcs, ctx);488ir3_prog_init(pctx);489fd_prog_init(pctx);490}491492493