static INLINE void * remote_context_create_vs_state(struct pipe_context *_pipe, const struct pipe_shader_state *state) { int tokens = tgsi_num_tokens(state->tokens); struct remreq_create_vs_state* header = allocate_message_memory( sizeof(struct remreq_create_vs_state) + (tokens * sizeof(struct tgsi_token))); uint32_t handle = get_fresh_vs_handle(_pipe->screen); DBG("Create new VS state: handle %u\n", handle); header->base.opcode = REMREQ_CREATE_VS_STATE; header->pipe = PIPE_HANDLE(_pipe); header->vs_handle = handle; char* copy_dest = ((char*)header) + sizeof(struct remreq_create_vs_state); memcpy(copy_dest, (char*)(state->tokens), sizeof(struct tgsi_token) * tokens); enqueue_message(header); struct opaque_remote_vs* retval = CALLOC_STRUCT(opaque_remote_vs); PANIC_IF_NULL(retval); retval->handle = handle; return retval; }
const struct tgsi_token * tgsi_emulate(const struct tgsi_token *tokens, unsigned flags) { struct tgsi_emulation_context ctx; struct tgsi_token *newtoks; int newlen; if (!(flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS | TGSI_EMU_PASSTHROUGH_EDGEFLAG | TGSI_EMU_FORCE_PERSAMPLE_INTERP))) return NULL; memset(&ctx, 0, sizeof(ctx)); ctx.flags = flags; tgsi_scan_shader(tokens, &ctx.info); if (flags & TGSI_EMU_FORCE_PERSAMPLE_INTERP) ctx.base.transform_declaration = transform_decl; if (flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS | TGSI_EMU_PASSTHROUGH_EDGEFLAG)) ctx.base.transform_instruction = transform_instr; newlen = tgsi_num_tokens(tokens) + 20; newtoks = tgsi_alloc_tokens(newlen); if (!newtoks) return NULL; tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base); return newtoks; }
/** * Make a new copy of a token array. */ struct tgsi_token * tgsi_dup_tokens(const struct tgsi_token *tokens) { unsigned n = tgsi_num_tokens(tokens); unsigned bytes = n * sizeof(struct tgsi_token); struct tgsi_token *new_tokens = (struct tgsi_token *) MALLOC(bytes); if (new_tokens) memcpy(new_tokens, tokens, bytes); return new_tokens; }
void tgsi_dump_tokens(const struct tgsi_token *tokens) { const unsigned *dwords = (const unsigned *)tokens; int nr = tgsi_num_tokens(tokens); int i; assert(sizeof(*tokens) == sizeof(unsigned)); debug_printf("const unsigned tokens[%d] = {\n", nr); for (i = 0; i < nr; i++) debug_printf("0x%08x,\n", dwords[i]); debug_printf("};\n"); }
/** * Generate the frag shader we'll use for drawing AA lines. * This will be the user's shader plus some texture/modulate instructions. */ static boolean generate_aaline_fs(struct aaline_stage *aaline) { struct pipe_context *pipe = aaline->stage.draw->pipe; const struct pipe_shader_state *orig_fs = &aaline->fs->state; struct pipe_shader_state aaline_fs; struct aa_transform_context transform; const uint newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS; aaline_fs = *orig_fs; /* copy to init */ aaline_fs.tokens = tgsi_alloc_tokens(newLen); if (aaline_fs.tokens == NULL) return FALSE; memset(&transform, 0, sizeof(transform)); transform.colorOutput = -1; transform.maxInput = -1; transform.maxGeneric = -1; transform.colorTemp = -1; transform.texTemp = -1; transform.base.prolog = aa_transform_prolog; transform.base.epilog = aa_transform_epilog; transform.base.transform_instruction = aa_transform_inst; transform.base.transform_declaration = aa_transform_decl; tgsi_transform_shader(orig_fs->tokens, (struct tgsi_token *) aaline_fs.tokens, newLen, &transform.base); #if 0 /* DEBUG */ debug_printf("draw_aaline, orig shader:\n"); tgsi_dump(orig_fs->tokens, 0); debug_printf("draw_aaline, new shader:\n"); tgsi_dump(aaline_fs.tokens, 0); #endif aaline->fs->sampler_unit = transform.freeSampler; aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs); if (aaline->fs->aaline_fs == NULL) goto fail; aaline->fs->generic_attrib = transform.maxGeneric + 1; FREE((void *)aaline_fs.tokens); return TRUE; fail: FREE((void *)aaline_fs.tokens); return FALSE; }
enum pipe_error cso_set_fragment_shader(struct cso_context *ctx, const struct pipe_shader_state *templ) { const struct tgsi_token *tokens = templ->tokens; unsigned num_tokens = tgsi_num_tokens(tokens); size_t tokens_size = num_tokens*sizeof(struct tgsi_token); unsigned hash_key = cso_construct_key((void*)tokens, tokens_size); struct cso_hash_iter iter = cso_find_state_template(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, (void*)tokens, sizeof(*templ)); /* XXX correct? tokens_size? */ void *handle = NULL; if (cso_hash_iter_is_null(iter)) { struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader) + tokens_size); struct tgsi_token *cso_tokens = (struct tgsi_token *)((char *)cso + sizeof(*cso)); if (!cso) return PIPE_ERROR_OUT_OF_MEMORY; memcpy(cso_tokens, tokens, tokens_size); cso->state.tokens = cso_tokens; cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state); cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state; cso->context = ctx->pipe; iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso); if (cso_hash_iter_is_null(iter)) { FREE(cso); return PIPE_ERROR_OUT_OF_MEMORY; } handle = cso->data; } else { handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data; } return cso_set_fragment_shader_handle( ctx, handle ); }
/* * A post-process step in the draw call to fix texture targets and * insert code for fog. */ const struct tgsi_token * st_fixup_atifs(const struct tgsi_token *tokens, const struct st_fp_variant_key *key) { struct tgsi_atifs_transform ctx; struct tgsi_token *newtoks; int newlen; memset(&ctx, 0, sizeof(ctx)); ctx.base.transform_declaration = transform_decl; ctx.base.transform_instruction = transform_instr; ctx.key = key; tgsi_scan_shader(tokens, &ctx.info); newlen = tgsi_num_tokens(tokens) + 30; newtoks = tgsi_alloc_tokens(newlen); if (!newtoks) return NULL; tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base); return newtoks; }
int virgl_encode_shader_state(struct virgl_context *ctx, uint32_t handle, uint32_t type, const struct pipe_stream_output_info *so_info, const struct tgsi_token *tokens) { char *str, *sptr; uint32_t shader_len, len; bool bret; int num_tokens = tgsi_num_tokens(tokens); int str_total_size = 65536; int retry_size = 1; uint32_t left_bytes, base_hdr_size, strm_hdr_size, thispass; bool first_pass; str = CALLOC(1, str_total_size); if (!str) return -1; do { int old_size; bret = tgsi_dump_str(tokens, TGSI_DUMP_FLOAT_AS_HEX, str, str_total_size); if (bret == false) { fprintf(stderr, "Failed to translate shader in available space - trying again\n"); old_size = str_total_size; str_total_size = 65536 * ++retry_size; str = REALLOC(str, old_size, str_total_size); if (!str) return -1; } } while (bret == false && retry_size < 10); if (bret == false) return -1; shader_len = strlen(str) + 1; left_bytes = shader_len; base_hdr_size = 5; strm_hdr_size = so_info->num_outputs ? so_info->num_outputs * 2 + 4 : 0; first_pass = true; sptr = str; while (left_bytes) { uint32_t length, offlen; int hdr_len = base_hdr_size + (first_pass ? strm_hdr_size : 0); if (ctx->cbuf->cdw + hdr_len + 1 > VIRGL_MAX_CMDBUF_DWORDS) ctx->base.flush(&ctx->base, NULL, 0); thispass = (VIRGL_MAX_CMDBUF_DWORDS - ctx->cbuf->cdw - hdr_len - 1) * 4; length = MIN2(thispass, left_bytes); len = ((length + 3) / 4) + hdr_len; if (first_pass) offlen = VIRGL_OBJ_SHADER_OFFSET_VAL(shader_len); else offlen = VIRGL_OBJ_SHADER_OFFSET_VAL((uintptr_t)sptr - (uintptr_t)str) | VIRGL_OBJ_SHADER_OFFSET_CONT; virgl_emit_shader_header(ctx, handle, len, type, offlen, num_tokens); virgl_emit_shader_streamout(ctx, first_pass ? so_info : NULL); virgl_encoder_write_block(ctx->cbuf, (uint8_t *)sptr, length); sptr += length; first_pass = false; left_bytes -= length; } FREE(str); return 0; }
void r300_draw_init_vertex_shader(struct r300_context *r300, struct r300_vertex_shader *vs) { struct draw_context *draw = r300->draw; struct pipe_shader_state new_vs; struct tgsi_shader_info info; struct vs_transform_context transform; const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */; unsigned i; tgsi_scan_shader(vs->state.tokens, &info); new_vs.tokens = tgsi_alloc_tokens(newLen); if (new_vs.tokens == NULL) return; memset(&transform, 0, sizeof(transform)); for (i = 0; i < Elements(transform.out_remap); i++) { transform.out_remap[i] = i; } transform.last_generic = -1; transform.base.transform_instruction = transform_inst; transform.base.transform_declaration = transform_decl; for (i = 0; i < info.num_outputs; i++) { unsigned index = info.output_semantic_index[i]; switch (info.output_semantic_name[i]) { case TGSI_SEMANTIC_COLOR: assert(index < 2); transform.color_used[index] = TRUE; break; case TGSI_SEMANTIC_BCOLOR: assert(index < 2); transform.bcolor_used[index] = TRUE; break; } } tgsi_transform_shader(vs->state.tokens, (struct tgsi_token*)new_vs.tokens, newLen, &transform.base); #if 0 printf("----------------------------------------------\norig shader:\n"); tgsi_dump(vs->state.tokens, 0); printf("----------------------------------------------\nnew shader:\n"); tgsi_dump(new_vs.tokens, 0); printf("----------------------------------------------\n"); #endif /* Free old tokens. */ FREE((void*)vs->state.tokens); vs->draw_vs = draw_create_vertex_shader(draw, &new_vs); /* Instead of duplicating and freeing the tokens, copy the pointer directly. */ vs->state.tokens = new_vs.tokens; /* Init the VS output table for the rasterizer. */ r300_init_vs_outputs(r300, vs); /* Make the last generic be WPOS. */ vs->outputs.wpos = vs->outputs.generic[transform.last_generic + 1]; vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED; }