/** * 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); }
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); }
/** * 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); }
/** * 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; } pipe_shader_state_from_tgsi(&state, tokens); 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; }
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); }