/** * Make simple fragment color pass-through shader that replicates OUT[0] * to all bound colorbuffers. */ void * util_make_fragment_passthrough_shader(struct pipe_context *pipe, int input_semantic, int input_interpolate, boolean write_all_cbufs) { static const char shader_templ[] = "FRAG\n" "%s" "DCL IN[0], %s[0], %s\n" "DCL OUT[0], COLOR[0]\n" "MOV OUT[0], IN[0]\n" "END\n"; char text[sizeof(shader_templ)+100]; struct tgsi_token tokens[1000]; struct pipe_shader_state state; sprintf(text, shader_templ, write_all_cbufs ? "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n" : "", tgsi_semantic_names[input_semantic], tgsi_interpolate_names[input_interpolate]); if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { assert(0); return NULL; } pipe_shader_state_from_tgsi(&state, tokens); #if 0 tgsi_dump(state.tokens, 0); #endif return pipe->create_fs_state(pipe, &state); }
/** * Takes position and color, and outputs position, color, and instance id. */ void *util_make_layered_clear_helper_vertex_shader(struct pipe_context *pipe) { static const char text[] = "VERT\n" "DCL IN[0]\n" "DCL IN[1]\n" "DCL SV[0], INSTANCEID\n" "DCL OUT[0], POSITION\n" "DCL OUT[1], GENERIC[0]\n" "DCL OUT[2], GENERIC[1]\n" "MOV OUT[0], IN[0]\n" "MOV OUT[1], IN[1]\n" "MOV OUT[2].x, SV[0].xxxx\n" "END\n"; struct tgsi_token tokens[1000]; struct pipe_shader_state state; if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { assert(0); return NULL; } pipe_shader_state_from_tgsi(&state, tokens); return pipe->create_vs_state(pipe, &state); }
void util_test_constant_buffer(struct pipe_context *ctx, struct pipe_resource *constbuf) { struct cso_context *cso; struct pipe_resource *cb; void *fs, *vs; bool pass = true; static const float zero[] = {0, 0, 0, 0}; cso = cso_create_context(ctx, 0); cb = util_create_texture2d(ctx->screen, 256, 256, PIPE_FORMAT_R8G8B8A8_UNORM, 0); util_set_common_states_and_clear(cso, ctx, cb); pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf); /* Fragment shader. */ { static const char *text = /* I don't like ureg... */ "FRAG\n" "DCL CONST[0][0]\n" "DCL OUT[0], COLOR\n" "MOV OUT[0], CONST[0][0]\n" "END\n"; struct tgsi_token tokens[1000]; struct pipe_shader_state state; if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { puts("Can't compile a fragment shader."); util_report_result(FAIL); return; } pipe_shader_state_from_tgsi(&state, tokens); fs = ctx->create_fs_state(ctx, &state); cso_set_fragment_shader_handle(cso, fs); } /* Vertex shader. */ vs = util_set_passthrough_vertex_shader(cso, ctx, false); util_draw_fullscreen_quad(cso); /* Probe pixels. */ pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0, cb->height0, zero); /* Cleanup. */ cso_destroy_context(cso); ctx->delete_vs_state(ctx, vs); ctx->delete_fs_state(ctx, fs); pipe_resource_reference(&cb, NULL); util_report_result(pass); }
int main(int argc, char **argv) { if(argc < 2) { fprintf(stderr, "Must pass shader source name as argument\n"); exit(1); } const char *text = load_text_file(argv[1]); if(!text) { fprintf(stderr, "Unable to open %s\n", argv[1]); exit(1); } struct tgsi_token tokens[1024]; if(tgsi_text_translate(text, tokens, Elements(tokens))) { tgsi_dump(tokens, 0); union { struct tgsi_header h; struct tgsi_token t; } hdr; hdr.t = tokens[0]; printf("Header size: %i\n", hdr.h.HeaderSize); printf("Body size: %i\n", hdr.h.BodySize); int totalSize = hdr.h.HeaderSize + hdr.h.BodySize; for(int i=0; i<totalSize; ++i) { printf("%08x ", *((uint32_t*)&tokens[i])); } printf("\n"); /* Parsing test */ struct tgsi_parse_context ctx = {}; unsigned status = TGSI_PARSE_OK; status = tgsi_parse_init(&ctx, tokens); assert(status == TGSI_PARSE_OK); while(!tgsi_parse_end_of_tokens(&ctx)) { tgsi_parse_token(&ctx); /* declaration / immediate / instruction / property */ printf("Parsed token! %i\n", ctx.FullToken.Token.Type); } tgsi_parse_free(&ctx); } else { fprintf(stderr, "Unable to parse %s\n", argv[1]); } return 0; }
static const struct tgsi_token *substitute_vs( unsigned shader_id, const struct tgsi_token *old_tokens ) { #if 0 if (shader_id == 12) { static struct tgsi_token tokens[300]; const char *text = "VERT1.1\n" "DCL IN[0]\n" "DCL IN[1]\n" "DCL IN[2]\n" "DCL OUT[0], POSITION\n" "DCL TEMP[0..4]\n" "IMM FLT32 { 1.0000, 1.0000, 1.0000, 1.0000 }\n" "IMM FLT32 { 0.45, 1.0000, 1.0000, 1.0000 }\n" "IMM FLT32 { 1.297863, 0.039245, 0.035993, 0.035976}\n" "IMM FLT32 { -0.019398, 1.696131, -0.202151, -0.202050 }\n" "IMM FLT32 { 0.051711, -0.348713, -0.979204, -0.978714 }\n" "IMM FLT32 { 0.000000, 0.000003, 139.491577, 141.421356 }\n" "DCL CONST[0..7]\n" "DCL CONST[9..16]\n" " MOV TEMP[2], IMM[0]\n" " MOV TEMP[2].xyz, IN[2]\n" " MOV TEMP[2].xyz, IN[0]\n" " MOV TEMP[2].xyz, IN[1]\n" " MUL TEMP[1], IMM[3], TEMP[2].yyyy\n" " MAD TEMP[3], IMM[2], TEMP[2].xxxx, TEMP[1]\n" " MAD TEMP[1], IMM[4], TEMP[2].zzzz, TEMP[3]\n" " MAD TEMP[4], IMM[5], TEMP[2].wwww, TEMP[1]\n" " MOV OUT[0], TEMP[4]\n" " END\n"; if (!tgsi_text_translate( text, tokens, Elements(tokens) )) { assert(0); return NULL; } return tokens; } #endif return old_tokens; }
static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens) { struct tgsi_token *tokens; tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0])); tgsi_text_translate(txt, tokens, num_tokens); #if DEBUG_SHADERS tgsi_dump(tokens, 0); #endif return tokens; }
static void * assemble_tgsi(struct pipe_context *pctx, const char *src, bool frag) { struct tgsi_token toks[32]; struct pipe_shader_state cso = { .tokens = toks, }; tgsi_text_translate(src, toks, ARRAY_SIZE(toks)); if (frag) return pctx->create_fs_state(pctx, &cso); else return pctx->create_vs_state(pctx, &cso); }
static void * util_make_fs_blit_msaa_gen(struct pipe_context *pipe, enum tgsi_texture_type tgsi_tex, const char *samp_type, const char *output_semantic, const char *output_mask, const char *conversion_decl, const char *conversion) { static const char shader_templ[] = "FRAG\n" "DCL IN[0], GENERIC[0], LINEAR\n" "DCL SAMP[0]\n" "DCL SVIEW[0], %s, %s\n" "DCL OUT[0], %s\n" "DCL TEMP[0]\n" "%s" "F2U TEMP[0], IN[0]\n" "TXF TEMP[0], TEMP[0], SAMP[0], %s\n" "%s" "MOV OUT[0]%s, TEMP[0]\n" "END\n"; const char *type = tgsi_texture_names[tgsi_tex]; char text[sizeof(shader_templ)+100]; struct tgsi_token tokens[1000]; struct pipe_shader_state state; assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); util_snprintf(text, sizeof(text), shader_templ, type, samp_type, output_semantic, conversion_decl, type, conversion, output_mask); if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { puts(text); assert(0); return NULL; } pipe_shader_state_from_tgsi(&state, tokens); #if 0 tgsi_dump(state.tokens, 0); #endif return pipe->create_fs_state(pipe, &state); }
/** * Convert the TGSI assembly to a runnable shader. * * We need not care about geometry shaders. All we have is screen quads. */ void * pp_tgsi_to_state(struct pipe_context *pipe, const char *text, bool isvs, const char *name) { struct pipe_shader_state state; struct tgsi_token tokens[PP_MAX_TOKENS]; if (tgsi_text_translate(text, tokens, Elements(tokens)) == FALSE) { pp_debug("Failed to translate %s\n", name); return NULL; } state.tokens = tokens; memset(&state.stream_output, 0, sizeof(state.stream_output)); if (isvs) return pipe->create_vs_state(pipe, &state); else return pipe->create_fs_state(pipe, &state); }
/** * Make a fragment shader that sets the output depth and stencil to depth * and stencil values fetched from two multisample textures / samplers. * The sizes of both textures should match (it should be one depth-stencil * texture). * \param tex_target one of PIPE_TEXTURE_x */ void * util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe, enum tgsi_texture_type tgsi_tex) { static const char shader_templ[] = "FRAG\n" "DCL IN[0], GENERIC[0], LINEAR\n" "DCL SAMP[0..1]\n" "DCL SVIEW[0..1], %s, FLOAT\n" "DCL OUT[0], POSITION\n" "DCL OUT[1], STENCIL\n" "DCL TEMP[0]\n" "F2U TEMP[0], IN[0]\n" "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n" "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n" "END\n"; const char *type = tgsi_texture_names[tgsi_tex]; char text[sizeof(shader_templ)+100]; struct tgsi_token tokens[1000]; struct pipe_shader_state state; assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); sprintf(text, shader_templ, type, type, type); if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { assert(0); return NULL; } pipe_shader_state_from_tgsi(&state, tokens); #if 0 tgsi_dump(state.tokens, 0); #endif return pipe->create_fs_state(pipe, &state); }
/** * Takes position, color, and target layer, and emits vertices on that target * layer, with the specified color. */ void *util_make_layered_clear_geometry_shader(struct pipe_context *pipe) { static const char text[] = "GEOM\n" "PROPERTY GS_INPUT_PRIMITIVE TRIANGLES\n" "PROPERTY GS_OUTPUT_PRIMITIVE TRIANGLE_STRIP\n" "PROPERTY GS_MAX_OUTPUT_VERTICES 3\n" "PROPERTY GS_INVOCATIONS 1\n" "DCL IN[][0], POSITION\n" /* position */ "DCL IN[][1], GENERIC[0]\n" /* color */ "DCL IN[][2], GENERIC[1]\n" /* vs invocation */ "DCL OUT[0], POSITION\n" "DCL OUT[1], GENERIC[0]\n" "DCL OUT[2], LAYER\n" "IMM[0] INT32 {0, 0, 0, 0}\n" "MOV OUT[0], IN[0][0]\n" "MOV OUT[1], IN[0][1]\n" "MOV OUT[2].x, IN[0][2].xxxx\n" "EMIT IMM[0].xxxx\n" "MOV OUT[0], IN[1][0]\n" "MOV OUT[1], IN[1][1]\n" "MOV OUT[2].x, IN[1][2].xxxx\n" "EMIT IMM[0].xxxx\n" "MOV OUT[0], IN[2][0]\n" "MOV OUT[1], IN[2][1]\n" "MOV OUT[2].x, IN[2][2].xxxx\n" "EMIT IMM[0].xxxx\n" "END\n"; struct tgsi_token tokens[1000]; struct pipe_shader_state state; if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { assert(0); return NULL; } pipe_shader_state_from_tgsi(&state, tokens); return pipe->create_gs_state(pipe, &state); }
static void * util_make_fs_blit_msaa_gen(struct pipe_context *pipe, unsigned tgsi_tex, const char *output_semantic, const char *output_mask) { static const char shader_templ[] = "FRAG\n" "DCL IN[0], GENERIC[0], LINEAR\n" "DCL SAMP[0]\n" "DCL OUT[0], %s\n" "DCL TEMP[0]\n" "F2U TEMP[0], IN[0]\n" "TXF OUT[0]%s, TEMP[0], SAMP[0], %s\n" "END\n"; const char *type = tgsi_texture_names[tgsi_tex]; char text[sizeof(shader_templ)+100]; struct tgsi_token tokens[1000]; struct pipe_shader_state state = {tokens}; assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); sprintf(text, shader_templ, output_semantic, output_mask, type); if (!tgsi_text_translate(text, tokens, Elements(tokens))) { puts(text); assert(0); return NULL; } #if 0 tgsi_dump(state.tokens, 0); #endif return pipe->create_fs_state(pipe, &state); }
/** * Convert the TGSI assembly to a runnable shader. * * We need not care about geometry shaders. All we have is screen quads. */ void * pp_tgsi_to_state(struct pipe_context *pipe, const char *text, bool isvs, const char *name) { struct pipe_shader_state state; struct tgsi_token *tokens = NULL; void *ret_state = NULL; /* * Allocate temporary token storage. State creation will duplicate * tokens so we must free them on exit. */ tokens = tgsi_alloc_tokens(PP_MAX_TOKENS); if (!tokens) { pp_debug("Failed to allocate temporary token storage.\n"); return NULL; } if (tgsi_text_translate(text, tokens, PP_MAX_TOKENS) == FALSE) { _debug_printf("pp: Failed to translate a shader for %s\n", name); return NULL; } state.tokens = tokens; memset(&state.stream_output, 0, sizeof(state.stream_output)); if (isvs) { ret_state = pipe->create_vs_state(pipe, &state); FREE(tokens); } else { ret_state = pipe->create_fs_state(pipe, &state); FREE(tokens); } return ret_state; }
/* Create the compute shader that is used to collect the results. * * One compute grid with a single thread is launched for every query result * buffer. The thread (optionally) reads a previous summary buffer, then * accumulates data from the query result buffer, and writes the result either * to a summary buffer to be consumed by the next grid invocation or to the * user-supplied buffer. * * Data layout: * * CONST * 0.x = end_offset * 0.y = result_stride * 0.z = result_count * 0.w = bit field: * 1: read previously accumulated values * 2: write accumulated values for chaining * 4: write result available * 8: convert result to boolean (0/1) * 16: only read one dword and use that as result * 32: apply timestamp conversion * 64: store full 64 bits result * 128: store signed 32 bits result * 256: SO_OVERFLOW mode: take the difference of two successive half-pairs * 1.x = fence_offset * 1.y = pair_stride * 1.z = pair_count * * BUFFER[0] = query result buffer * BUFFER[1] = previous summary buffer * BUFFER[2] = next summary buffer or user-supplied buffer */ void *si_create_query_result_cs(struct si_context *sctx) { /* TEMP[0].xy = accumulated result so far * TEMP[0].z = result not available * * TEMP[1].x = current result index * TEMP[1].y = current pair index */ static const char text_tmpl[] = "COMP\n" "PROPERTY CS_FIXED_BLOCK_WIDTH 1\n" "PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n" "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n" "DCL BUFFER[0]\n" "DCL BUFFER[1]\n" "DCL BUFFER[2]\n" "DCL CONST[0][0..1]\n" "DCL TEMP[0..5]\n" "IMM[0] UINT32 {0, 31, 2147483647, 4294967295}\n" "IMM[1] UINT32 {1, 2, 4, 8}\n" "IMM[2] UINT32 {16, 32, 64, 128}\n" "IMM[3] UINT32 {1000000, 0, %u, 0}\n" /* for timestamp conversion */ "IMM[4] UINT32 {256, 0, 0, 0}\n" "AND TEMP[5], CONST[0][0].wwww, IMM[2].xxxx\n" "UIF TEMP[5]\n" /* Check result availability. */ "LOAD TEMP[1].x, BUFFER[0], CONST[0][1].xxxx\n" "ISHR TEMP[0].z, TEMP[1].xxxx, IMM[0].yyyy\n" "MOV TEMP[1], TEMP[0].zzzz\n" "NOT TEMP[0].z, TEMP[0].zzzz\n" /* Load result if available. */ "UIF TEMP[1]\n" "LOAD TEMP[0].xy, BUFFER[0], IMM[0].xxxx\n" "ENDIF\n" "ELSE\n" /* Load previously accumulated result if requested. */ "MOV TEMP[0], IMM[0].xxxx\n" "AND TEMP[4], CONST[0][0].wwww, IMM[1].xxxx\n" "UIF TEMP[4]\n" "LOAD TEMP[0].xyz, BUFFER[1], IMM[0].xxxx\n" "ENDIF\n" "MOV TEMP[1].x, IMM[0].xxxx\n" "BGNLOOP\n" /* Break if accumulated result so far is not available. */ "UIF TEMP[0].zzzz\n" "BRK\n" "ENDIF\n" /* Break if result_index >= result_count. */ "USGE TEMP[5], TEMP[1].xxxx, CONST[0][0].zzzz\n" "UIF TEMP[5]\n" "BRK\n" "ENDIF\n" /* Load fence and check result availability */ "UMAD TEMP[5].x, TEMP[1].xxxx, CONST[0][0].yyyy, CONST[0][1].xxxx\n" "LOAD TEMP[5].x, BUFFER[0], TEMP[5].xxxx\n" "ISHR TEMP[0].z, TEMP[5].xxxx, IMM[0].yyyy\n" "NOT TEMP[0].z, TEMP[0].zzzz\n" "UIF TEMP[0].zzzz\n" "BRK\n" "ENDIF\n" "MOV TEMP[1].y, IMM[0].xxxx\n" "BGNLOOP\n" /* Load start and end. */ "UMUL TEMP[5].x, TEMP[1].xxxx, CONST[0][0].yyyy\n" "UMAD TEMP[5].x, TEMP[1].yyyy, CONST[0][1].yyyy, TEMP[5].xxxx\n" "LOAD TEMP[2].xy, BUFFER[0], TEMP[5].xxxx\n" "UADD TEMP[5].y, TEMP[5].xxxx, CONST[0][0].xxxx\n" "LOAD TEMP[3].xy, BUFFER[0], TEMP[5].yyyy\n" "U64ADD TEMP[4].xy, TEMP[3], -TEMP[2]\n" "AND TEMP[5].z, CONST[0][0].wwww, IMM[4].xxxx\n" "UIF TEMP[5].zzzz\n" /* Load second start/end half-pair and * take the difference */ "UADD TEMP[5].xy, TEMP[5], IMM[1].wwww\n" "LOAD TEMP[2].xy, BUFFER[0], TEMP[5].xxxx\n" "LOAD TEMP[3].xy, BUFFER[0], TEMP[5].yyyy\n" "U64ADD TEMP[3].xy, TEMP[3], -TEMP[2]\n" "U64ADD TEMP[4].xy, TEMP[4], -TEMP[3]\n" "ENDIF\n" "U64ADD TEMP[0].xy, TEMP[0], TEMP[4]\n" /* Increment pair index */ "UADD TEMP[1].y, TEMP[1].yyyy, IMM[1].xxxx\n" "USGE TEMP[5], TEMP[1].yyyy, CONST[0][1].zzzz\n" "UIF TEMP[5]\n" "BRK\n" "ENDIF\n" "ENDLOOP\n" /* Increment result index */ "UADD TEMP[1].x, TEMP[1].xxxx, IMM[1].xxxx\n" "ENDLOOP\n" "ENDIF\n" "AND TEMP[4], CONST[0][0].wwww, IMM[1].yyyy\n" "UIF TEMP[4]\n" /* Store accumulated data for chaining. */ "STORE BUFFER[2].xyz, IMM[0].xxxx, TEMP[0]\n" "ELSE\n" "AND TEMP[4], CONST[0][0].wwww, IMM[1].zzzz\n" "UIF TEMP[4]\n" /* Store result availability. */ "NOT TEMP[0].z, TEMP[0]\n" "AND TEMP[0].z, TEMP[0].zzzz, IMM[1].xxxx\n" "STORE BUFFER[2].x, IMM[0].xxxx, TEMP[0].zzzz\n" "AND TEMP[4], CONST[0][0].wwww, IMM[2].zzzz\n" "UIF TEMP[4]\n" "STORE BUFFER[2].y, IMM[0].xxxx, IMM[0].xxxx\n" "ENDIF\n" "ELSE\n" /* Store result if it is available. */ "NOT TEMP[4], TEMP[0].zzzz\n" "UIF TEMP[4]\n" /* Apply timestamp conversion */ "AND TEMP[4], CONST[0][0].wwww, IMM[2].yyyy\n" "UIF TEMP[4]\n" "U64MUL TEMP[0].xy, TEMP[0], IMM[3].xyxy\n" "U64DIV TEMP[0].xy, TEMP[0], IMM[3].zwzw\n" "ENDIF\n" /* Convert to boolean */ "AND TEMP[4], CONST[0][0].wwww, IMM[1].wwww\n" "UIF TEMP[4]\n" "U64SNE TEMP[0].x, TEMP[0].xyxy, IMM[4].zwzw\n" "AND TEMP[0].x, TEMP[0].xxxx, IMM[1].xxxx\n" "MOV TEMP[0].y, IMM[0].xxxx\n" "ENDIF\n" "AND TEMP[4], CONST[0][0].wwww, IMM[2].zzzz\n" "UIF TEMP[4]\n" "STORE BUFFER[2].xy, IMM[0].xxxx, TEMP[0].xyxy\n" "ELSE\n" /* Clamping */ "UIF TEMP[0].yyyy\n" "MOV TEMP[0].x, IMM[0].wwww\n" "ENDIF\n" "AND TEMP[4], CONST[0][0].wwww, IMM[2].wwww\n" "UIF TEMP[4]\n" "UMIN TEMP[0].x, TEMP[0].xxxx, IMM[0].zzzz\n" "ENDIF\n" "STORE BUFFER[2].x, IMM[0].xxxx, TEMP[0].xxxx\n" "ENDIF\n" "ENDIF\n" "ENDIF\n" "ENDIF\n" "END\n"; char text[sizeof(text_tmpl) + 32]; struct tgsi_token tokens[1024]; struct pipe_compute_state state = {}; /* Hard code the frequency into the shader so that the backend can * use the full range of optimizations for divide-by-constant. */ snprintf(text, sizeof(text), text_tmpl, sctx->screen->info.clock_crystal_freq); if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { assert(false); return NULL; } state.ir_type = PIPE_SHADER_IR_TGSI; state.prog = tokens; return sctx->b.create_compute_state(&sctx->b, &state); }
int main(int argc, char *argv[]) { struct tgsi_token tokens[4096]; int i, chipset = 0, type = -1; const char *filename = NULL; FILE *f; char text[65536] = {0}; unsigned size, *code; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-a")) chipset = strtol(argv[++i], NULL, 16); else filename = argv[i]; } if (!chipset) { _debug_printf("Must specify a chipset (-a)\n"); return 1; } if (!filename) { _debug_printf("Must specify a filename\n"); return 1; } if (!strcmp(filename, "-")) f = stdin; else f = fopen(filename, "r"); if (f == NULL) { _debug_printf("Error opening file '%s': %s\n", filename, strerror(errno)); return 1; } if (!fread(text, 1, sizeof(text), f) || ferror(f)) { _debug_printf("Error reading file '%s'\n", filename); fclose(f); return 1; } fclose(f); _debug_printf("Compiling for NV%X\n", chipset); if (!strncmp(text, "FRAG", 4)) type = PIPE_SHADER_FRAGMENT; else if (!strncmp(text, "VERT", 4)) type = PIPE_SHADER_VERTEX; else if (!strncmp(text, "GEOM", 4)) type = PIPE_SHADER_GEOMETRY; else if (!strncmp(text, "COMP", 4)) type = PIPE_SHADER_COMPUTE; else { _debug_printf("Unrecognized TGSI header\n"); return 1; } if (!tgsi_text_translate(text, tokens, Elements(tokens))) { _debug_printf("Failed to parse TGSI shader\n"); return 1; } if (chipset >= 0x50) { i = nouveau_codegen(chipset, type, tokens, &size, &code); } else if (chipset >= 0x30) { i = nv30_codegen(chipset, type, tokens, &size, &code); } else { _debug_printf("chipset NV%02X not supported\n", chipset); i = 1; } if (i) return i; _debug_printf("program binary (%d bytes)\n", size); for (i = 0; i < size; i += 4) { printf("%08x ", code[i / 4]); if (i % (8 * 4) == (7 * 4)) printf("\n"); } if (i % (8 * 4) != 0) printf("\n"); return 0; }
int main(int argc, char **argv) { int ret = 0, n = 1; const char *filename; struct tgsi_token toks[65536]; struct tgsi_parse_context parse; struct ir3_compiler *compiler; struct ir3_shader_variant v; struct ir3_shader_key key = {}; const char *info; void *ptr; size_t size; fd_mesa_debug |= FD_DBG_DISASM; /* cmdline args which impact shader variant get spit out in a * comment on the first line.. a quick/dirty way to preserve * that info so when ir3test recompiles the shader with a new * compiler version, we use the same shader-key settings: */ debug_printf("; options:"); while (n < argc) { if (!strcmp(argv[n], "--verbose")) { fd_mesa_debug |= FD_DBG_MSGS | FD_DBG_OPTMSGS; n++; continue; } if (!strcmp(argv[n], "--binning-pass")) { debug_printf(" %s", argv[n]); key.binning_pass = true; n++; continue; } if (!strcmp(argv[n], "--color-two-side")) { debug_printf(" %s", argv[n]); key.color_two_side = true; n++; continue; } if (!strcmp(argv[n], "--half-precision")) { debug_printf(" %s", argv[n]); key.half_precision = true; n++; continue; } if (!strcmp(argv[n], "--saturate-s")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vsaturate_s = key.fsaturate_s = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--saturate-t")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vsaturate_t = key.fsaturate_t = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--saturate-r")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vsaturate_r = key.fsaturate_r = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--help")) { print_usage(); return 0; } break; } debug_printf("\n"); filename = argv[n]; memset(&v, 0, sizeof(v)); v.key = key; ret = read_file(filename, &ptr, &size); if (ret) { print_usage(); return ret; } if (fd_mesa_debug & FD_DBG_OPTMSGS) debug_printf("%s\n", (char *)ptr); if (!tgsi_text_translate(ptr, toks, Elements(toks))) errx(1, "could not parse `%s'", filename); tgsi_parse_init(&parse, toks); switch (parse.FullHeader.Processor.Processor) { case TGSI_PROCESSOR_FRAGMENT: v.type = SHADER_FRAGMENT; break; case TGSI_PROCESSOR_VERTEX: v.type = SHADER_VERTEX; break; case TGSI_PROCESSOR_COMPUTE: v.type = SHADER_COMPUTE; break; } /* TODO cmdline option to target different gpus: */ compiler = ir3_compiler_create(320); info = "NIR compiler"; ret = ir3_compile_shader_nir(compiler, &v, toks, key); if (ret) { fprintf(stderr, "compiler failed!\n"); return ret; } dump_info(&v, info); }
int main(int argc, char **argv) { int ret = 0, n = 1; char *filenames[2]; int num_files = 0; unsigned stage = 0; struct ir3_shader_variant v; struct ir3_shader s; struct ir3_shader_key key = {}; /* TODO cmdline option to target different gpus: */ unsigned gpu_id = 320; const char *info; void *ptr; size_t size; memset(&s, 0, sizeof(s)); memset(&v, 0, sizeof(v)); /* cmdline args which impact shader variant get spit out in a * comment on the first line.. a quick/dirty way to preserve * that info so when ir3test recompiles the shader with a new * compiler version, we use the same shader-key settings: */ debug_printf("; options:"); while (n < argc) { if (!strcmp(argv[n], "--verbose")) { fd_mesa_debug |= FD_DBG_MSGS | FD_DBG_OPTMSGS | FD_DBG_DISASM; n++; continue; } if (!strcmp(argv[n], "--binning-pass")) { debug_printf(" %s", argv[n]); key.binning_pass = true; n++; continue; } if (!strcmp(argv[n], "--color-two-side")) { debug_printf(" %s", argv[n]); key.color_two_side = true; n++; continue; } if (!strcmp(argv[n], "--half-precision")) { debug_printf(" %s", argv[n]); key.half_precision = true; n++; continue; } if (!strcmp(argv[n], "--saturate-s")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vsaturate_s = key.fsaturate_s = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--saturate-t")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vsaturate_t = key.fsaturate_t = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--saturate-r")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vsaturate_r = key.fsaturate_r = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--astc-srgb")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.vastc_srgb = key.fastc_srgb = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--stream-out")) { struct pipe_stream_output_info *so = &s.stream_output; debug_printf(" %s", argv[n]); /* TODO more dynamic config based on number of outputs, etc * rather than just hard-code for first output: */ so->num_outputs = 1; so->stride[0] = 4; so->output[0].register_index = 0; so->output[0].start_component = 0; so->output[0].num_components = 4; so->output[0].output_buffer = 0; so->output[0].dst_offset = 2; so->output[0].stream = 0; n++; continue; } if (!strcmp(argv[n], "--ucp")) { debug_printf(" %s %s", argv[n], argv[n+1]); key.ucp_enables = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--gpu")) { debug_printf(" %s %s", argv[n], argv[n+1]); gpu_id = strtol(argv[n+1], NULL, 0); n += 2; continue; } if (!strcmp(argv[n], "--help")) { print_usage(); return 0; } break; } debug_printf("\n"); while (n < argc) { char *filename = argv[n]; char *ext = rindex(filename, '.'); if (strcmp(ext, ".tgsi") == 0) { if (num_files != 0) errx(1, "in TGSI mode, only a single file may be specified"); s.from_tgsi = true; } else if (strcmp(ext, ".frag") == 0) { if (s.from_tgsi) errx(1, "cannot mix GLSL and TGSI"); if (num_files >= ARRAY_SIZE(filenames)) errx(1, "too many GLSL files"); stage = MESA_SHADER_FRAGMENT; } else if (strcmp(ext, ".vert") == 0) { if (s.from_tgsi) errx(1, "cannot mix GLSL and TGSI"); if (num_files >= ARRAY_SIZE(filenames)) errx(1, "too many GLSL files"); stage = MESA_SHADER_VERTEX; } else { print_usage(); return -1; } filenames[num_files++] = filename; n++; } nir_shader *nir; if (s.from_tgsi) { struct tgsi_token toks[65536]; ret = read_file(filenames[0], &ptr, &size); if (ret) { print_usage(); return ret; } if (fd_mesa_debug & FD_DBG_OPTMSGS) debug_printf("%s\n", (char *)ptr); if (!tgsi_text_translate(ptr, toks, ARRAY_SIZE(toks))) errx(1, "could not parse `%s'", filenames[0]); if (fd_mesa_debug & FD_DBG_OPTMSGS) tgsi_dump(toks, 0); nir = ir3_tgsi_to_nir(toks); } else if (num_files > 0) { nir = load_glsl(num_files, filenames, stage); } else { print_usage(); return -1; } s.compiler = ir3_compiler_create(NULL, gpu_id); s.nir = ir3_optimize_nir(&s, nir, NULL); v.key = key; v.shader = &s; switch (nir->stage) { case MESA_SHADER_FRAGMENT: s.type = v.type = SHADER_FRAGMENT; break; case MESA_SHADER_VERTEX: s.type = v.type = SHADER_VERTEX; break; case MESA_SHADER_COMPUTE: s.type = v.type = SHADER_COMPUTE; break; default: errx(1, "unhandled shader stage: %d", nir->stage); } info = "NIR compiler"; ret = ir3_compile_shader_nir(s.compiler, &v); if (ret) { fprintf(stderr, "compiler failed!\n"); return ret; } dump_info(&v, info); }
static void test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch, unsigned num_samples) { struct cso_context *cso; struct pipe_resource *cb; struct pipe_sampler_view *view = NULL; char name[256]; const char *text; assert(num_samples >= 1 && num_samples <= 8); util_snprintf(name, sizeof(name), "%s: %s, %u samples", __func__, use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1)); if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) { util_report_result_helper(SKIP, name); return; } if (use_fbfetch && !ctx->screen->get_param(ctx->screen, PIPE_CAP_TGSI_FS_FBFETCH)) { util_report_result_helper(SKIP, name); return; } cso = cso_create_context(ctx, 0); cb = util_create_texture2d(ctx->screen, 256, 256, PIPE_FORMAT_R8G8B8A8_UNORM, num_samples); util_set_common_states_and_clear(cso, ctx, cb); /* Clear each sample to a different value. */ if (num_samples > 1) { void *fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC, TGSI_INTERPOLATE_LINEAR, TRUE); cso_set_fragment_shader_handle(cso, fs); /* Vertex shader. */ void *vs = util_set_passthrough_vertex_shader(cso, ctx, false); for (unsigned i = 0; i < num_samples / 2; i++) { float value; /* 2 consecutive samples should have the same color to test MSAA * compression properly. */ if (num_samples == 2) { value = 0.1; } else { /* The average value must be 0.1 */ static const float values[] = { 0.0, 0.2, 0.05, 0.15 }; value = values[i]; } ctx->set_sample_mask(ctx, 0x3 << (i * 2)); util_draw_fullscreen_quad_fill(cso, value, value, value, value); } ctx->set_sample_mask(ctx, ~0); cso_set_vertex_shader_handle(cso, NULL); cso_set_fragment_shader_handle(cso, NULL); ctx->delete_vs_state(ctx, vs); ctx->delete_fs_state(ctx, fs); } if (use_fbfetch) { /* Fragment shader. */ text = "FRAG\n" "DCL OUT[0], COLOR[0]\n" "DCL TEMP[0]\n" "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" "FBFETCH TEMP[0], OUT[0]\n" "ADD OUT[0], TEMP[0], IMM[0]\n" "END\n"; } else { struct pipe_sampler_view templ = {{0}}; templ.format = cb->format; templ.target = cb->target; templ.swizzle_r = PIPE_SWIZZLE_X; templ.swizzle_g = PIPE_SWIZZLE_Y; templ.swizzle_b = PIPE_SWIZZLE_Z; templ.swizzle_a = PIPE_SWIZZLE_W; view = ctx->create_sampler_view(ctx, cb, &templ); ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &view); /* Fragment shader. */ if (num_samples > 1) { text = "FRAG\n" "DCL SV[0], POSITION\n" "DCL SV[1], SAMPLEID\n" "DCL SAMP[0]\n" "DCL SVIEW[0], 2D_MSAA, FLOAT\n" "DCL OUT[0], COLOR[0]\n" "DCL TEMP[0]\n" "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" "F2I TEMP[0].xy, SV[0].xyyy\n" "MOV TEMP[0].w, SV[1].xxxx\n" "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n" "ADD OUT[0], TEMP[0], IMM[0]\n" "END\n"; } else { text = "FRAG\n" "DCL SV[0], POSITION\n" "DCL SAMP[0]\n" "DCL SVIEW[0], 2D, FLOAT\n" "DCL OUT[0], COLOR[0]\n" "DCL TEMP[0]\n" "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" "IMM[1] INT32 { 0, 0, 0, 0}\n" "F2I TEMP[0].xy, SV[0].xyyy\n" "MOV TEMP[0].zw, IMM[1]\n" "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n" "ADD OUT[0], TEMP[0], IMM[0]\n" "END\n"; } } struct tgsi_token tokens[1000]; struct pipe_shader_state state; if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { assert(0); util_report_result_helper(FAIL, name); return; } pipe_shader_state_from_tgsi(&state, tokens); void *fs = ctx->create_fs_state(ctx, &state); cso_set_fragment_shader_handle(cso, fs); /* Vertex shader. */ void *vs = util_set_passthrough_vertex_shader(cso, ctx, false); if (num_samples > 1 && !use_fbfetch) ctx->set_min_samples(ctx, num_samples); for (int i = 0; i < 2; i++) { ctx->texture_barrier(ctx, use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER : PIPE_TEXTURE_BARRIER_SAMPLER); util_draw_fullscreen_quad(cso); } if (num_samples > 1 && !use_fbfetch) ctx->set_min_samples(ctx, 1); /* Probe pixels. * * For single sample: * result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9) * * For MSAA 4x: * sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8) * sample1 = sample0 * sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0) * sample3 = sample2 * resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9) */ static const float expected[] = {0.3, 0.5, 0.7, 0.9}; bool pass = util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0, cb->height0, expected); /* Cleanup. */ cso_destroy_context(cso); ctx->delete_vs_state(ctx, vs); ctx->delete_fs_state(ctx, fs); pipe_sampler_view_reference(&view, NULL); pipe_resource_reference(&cb, NULL); util_report_result_helper(pass, name); }