Home | History | Annotate | Download | only in util
      1 /**************************************************************************
      2  *
      3  * Copyright 2014 Advanced Micro Devices, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include "util/u_tests.h"
     29 
     30 #include "util/u_draw_quad.h"
     31 #include "util/u_format.h"
     32 #include "util/u_inlines.h"
     33 #include "util/u_memory.h"
     34 #include "util/u_simple_shaders.h"
     35 #include "util/u_surface.h"
     36 #include "util/u_string.h"
     37 #include "util/u_tile.h"
     38 #include "tgsi/tgsi_strings.h"
     39 #include "tgsi/tgsi_text.h"
     40 #include "cso_cache/cso_context.h"
     41 #include <stdio.h>
     42 
     43 #define TOLERANCE 0.01
     44 
     45 static struct pipe_resource *
     46 util_create_texture2d(struct pipe_screen *screen, unsigned width,
     47                       unsigned height, enum pipe_format format)
     48 {
     49    struct pipe_resource templ = {{0}};
     50 
     51    templ.target = PIPE_TEXTURE_2D;
     52    templ.width0 = width;
     53    templ.height0 = height;
     54    templ.depth0 = 1;
     55    templ.array_size = 1;
     56    templ.format = format;
     57    templ.usage = PIPE_USAGE_DEFAULT;
     58    templ.bind = PIPE_BIND_SAMPLER_VIEW |
     59                 (util_format_is_depth_or_stencil(format) ?
     60                     PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
     61 
     62    return screen->resource_create(screen, &templ);
     63 }
     64 
     65 static void
     66 util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
     67 			 struct pipe_resource *tex)
     68 {
     69    struct pipe_surface templ = {{0}}, *surf;
     70    struct pipe_framebuffer_state fb = {0};
     71 
     72    templ.format = tex->format;
     73    surf = ctx->create_surface(ctx, tex, &templ);
     74 
     75    fb.width = tex->width0;
     76    fb.height = tex->height0;
     77    fb.cbufs[0] = surf;
     78    fb.nr_cbufs = 1;
     79 
     80    cso_set_framebuffer(cso, &fb);
     81    pipe_surface_reference(&surf, NULL);
     82 }
     83 
     84 static void
     85 util_set_blend_normal(struct cso_context *cso)
     86 {
     87    struct pipe_blend_state blend = {0};
     88 
     89    blend.rt[0].colormask = PIPE_MASK_RGBA;
     90    cso_set_blend(cso, &blend);
     91 }
     92 
     93 static void
     94 util_set_dsa_disable(struct cso_context *cso)
     95 {
     96    struct pipe_depth_stencil_alpha_state dsa = {{0}};
     97 
     98    cso_set_depth_stencil_alpha(cso, &dsa);
     99 }
    100 
    101 static void
    102 util_set_rasterizer_normal(struct cso_context *cso)
    103 {
    104    struct pipe_rasterizer_state rs = {0};
    105 
    106    rs.half_pixel_center = 1;
    107    rs.bottom_edge_rule = 1;
    108    rs.depth_clip = 1;
    109 
    110    cso_set_rasterizer(cso, &rs);
    111 }
    112 
    113 static void
    114 util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
    115 {
    116    struct pipe_viewport_state viewport;
    117 
    118    viewport.scale[0] = 0.5f * tex->width0;
    119    viewport.scale[1] = 0.5f * tex->height0;
    120    viewport.scale[2] = 1.0f;
    121    viewport.translate[0] = 0.5f * tex->width0;
    122    viewport.translate[1] = 0.5f * tex->height0;
    123    viewport.translate[2] = 0.0f;
    124 
    125    cso_set_viewport(cso, &viewport);
    126 }
    127 
    128 static void
    129 util_set_interleaved_vertex_elements(struct cso_context *cso,
    130                                      unsigned num_elements)
    131 {
    132    unsigned i;
    133    struct pipe_vertex_element *velem =
    134       calloc(1, num_elements * sizeof(struct pipe_vertex_element));
    135 
    136    for (i = 0; i < num_elements; i++) {
    137       velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
    138       velem[i].src_offset = i * 16;
    139    }
    140 
    141    cso_set_vertex_elements(cso, num_elements, velem);
    142    free(velem);
    143 }
    144 
    145 static void *
    146 util_set_passthrough_vertex_shader(struct cso_context *cso,
    147                                    struct pipe_context *ctx,
    148                                    bool window_space)
    149 {
    150    static const uint vs_attribs[] = {
    151       TGSI_SEMANTIC_POSITION,
    152       TGSI_SEMANTIC_GENERIC
    153    };
    154    static const uint vs_indices[] = {0, 0};
    155    void *vs;
    156 
    157    vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
    158                                             window_space);
    159    cso_set_vertex_shader_handle(cso, vs);
    160    return vs;
    161 }
    162 
    163 static void
    164 util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
    165                                  struct pipe_resource *cb)
    166 {
    167    static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
    168 
    169    util_set_framebuffer_cb0(cso, ctx, cb);
    170    util_set_blend_normal(cso);
    171    util_set_dsa_disable(cso);
    172    util_set_rasterizer_normal(cso);
    173    util_set_max_viewport(cso, cb);
    174 
    175    ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
    176 }
    177 
    178 static void
    179 util_draw_fullscreen_quad(struct cso_context *cso)
    180 {
    181    static float vertices[] = {
    182      -1, -1, 0, 1,   0, 0, 0, 0,
    183      -1,  1, 0, 1,   0, 1, 0, 0,
    184       1,  1, 0, 1,   1, 1, 0, 0,
    185       1, -1, 0, 1,   1, 0, 0, 0
    186    };
    187    util_set_interleaved_vertex_elements(cso, 2);
    188    util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
    189 }
    190 
    191 /**
    192  * Probe and test if the rectangle contains the expected color.
    193  *
    194  * If "num_expected_colors" > 1, at least one expected color must match
    195  * the probed color. "expected" should be an array of 4*num_expected_colors
    196  * floats.
    197  */
    198 static bool
    199 util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
    200                            unsigned offx, unsigned offy, unsigned w,
    201                            unsigned h,
    202                            const float *expected,
    203                            unsigned num_expected_colors)
    204 {
    205    struct pipe_transfer *transfer;
    206    void *map;
    207    float *pixels = malloc(w * h * 4 * sizeof(float));
    208    unsigned x,y,e,c;
    209    bool pass = true;
    210 
    211    map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
    212                            offx, offy, w, h, &transfer);
    213    pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
    214    pipe_transfer_unmap(ctx, transfer);
    215 
    216    for (e = 0; e < num_expected_colors; e++) {
    217       for (y = 0; y < h; y++) {
    218          for (x = 0; x < w; x++) {
    219             float *probe = &pixels[(y*w + x)*4];
    220 
    221             for (c = 0; c < 4; c++) {
    222                if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
    223                   if (e < num_expected_colors-1)
    224                      goto next_color; /* test the next expected color */
    225 
    226                   printf("Probe color at (%i,%i),  ", offx+x, offy+y);
    227                   printf("Expected: %.3f, %.3f, %.3f, %.3f,  ",
    228                          expected[e*4], expected[e*4+1],
    229                          expected[e*4+2], expected[e*4+3]);
    230                   printf("Got: %.3f, %.3f, %.3f, %.3f\n",
    231                          probe[0], probe[1], probe[2], probe[2]);
    232                   pass = false;
    233                   goto done;
    234                }
    235             }
    236          }
    237       }
    238       break; /* this color was successful */
    239 
    240    next_color:;
    241    }
    242 done:
    243 
    244    free(pixels);
    245    return pass;
    246 }
    247 
    248 static bool
    249 util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
    250                      unsigned offx, unsigned offy, unsigned w, unsigned h,
    251                      const float *expected)
    252 {
    253    return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
    254 }
    255 
    256 enum {
    257    SKIP = -1,
    258    FAIL = 0, /* also "false" */
    259    PASS = 1 /* also "true" */
    260 };
    261 
    262 static void
    263 util_report_result_helper(int status, const char *name, ...)
    264 {
    265    char buf[256];
    266    va_list ap;
    267 
    268    va_start(ap, name);
    269    util_vsnprintf(buf, sizeof(buf), name, ap);
    270    va_end(ap);
    271 
    272    printf("Test(%s) = %s\n", buf,
    273           status == SKIP ? "skip" :
    274           status == PASS ? "pass" : "fail");
    275 }
    276 
    277 #define util_report_result(status) util_report_result_helper(status, __func__)
    278 
    279 /**
    280  * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
    281  *
    282  * The viewport state is set as usual, but it should have no effect.
    283  * Clipping should also be disabled.
    284  *
    285  * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
    286  * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
    287  * multiplied by 1/w (otherwise nothing would be rendered).
    288  *
    289  * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
    290  *       during perspective interpolation is not tested.
    291  */
    292 static void
    293 tgsi_vs_window_space_position(struct pipe_context *ctx)
    294 {
    295    struct cso_context *cso;
    296    struct pipe_resource *cb;
    297    void *fs, *vs;
    298    bool pass = true;
    299    static const float red[] = {1, 0, 0, 1};
    300 
    301    if (!ctx->screen->get_param(ctx->screen,
    302                                PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
    303       util_report_result(SKIP);
    304       return;
    305    }
    306 
    307    cso = cso_create_context(ctx);
    308    cb = util_create_texture2d(ctx->screen, 256, 256,
    309                               PIPE_FORMAT_R8G8B8A8_UNORM);
    310    util_set_common_states_and_clear(cso, ctx, cb);
    311 
    312    /* Fragment shader. */
    313    fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
    314                                        TGSI_INTERPOLATE_LINEAR, TRUE);
    315    cso_set_fragment_shader_handle(cso, fs);
    316 
    317    /* Vertex shader. */
    318    vs = util_set_passthrough_vertex_shader(cso, ctx, true);
    319 
    320    /* Draw. */
    321    {
    322       static float vertices[] = {
    323           0,   0, 0, 0,   1,  0, 0, 1,
    324           0, 256, 0, 0,   1,  0, 0, 1,
    325         256, 256, 0, 0,   1,  0, 0, 1,
    326         256,   0, 0, 0,   1,  0, 0, 1,
    327       };
    328       util_set_interleaved_vertex_elements(cso, 2);
    329       util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
    330    }
    331 
    332    /* Probe pixels. */
    333    pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
    334                                        cb->width0, cb->height0, red);
    335 
    336    /* Cleanup. */
    337    cso_destroy_context(cso);
    338    ctx->delete_vs_state(ctx, vs);
    339    ctx->delete_fs_state(ctx, fs);
    340    pipe_resource_reference(&cb, NULL);
    341 
    342    util_report_result(pass);
    343 }
    344 
    345 static void
    346 null_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target)
    347 {
    348    struct cso_context *cso;
    349    struct pipe_resource *cb;
    350    void *fs, *vs;
    351    bool pass = true;
    352    /* 2 expected colors: */
    353    static const float expected_tex[] = {0, 0, 0, 1,
    354                                         0, 0, 0, 0};
    355    static const float expected_buf[] = {0, 0, 0, 0};
    356    const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ?
    357                               expected_buf : expected_tex;
    358    unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2;
    359 
    360    if (tgsi_tex_target == TGSI_TEXTURE_BUFFER &&
    361        !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) {
    362       util_report_result_helper(SKIP, "%s: %s", __func__,
    363                                 tgsi_texture_names[tgsi_tex_target]);
    364       return;
    365    }
    366 
    367    cso = cso_create_context(ctx);
    368    cb = util_create_texture2d(ctx->screen, 256, 256,
    369                               PIPE_FORMAT_R8G8B8A8_UNORM);
    370    util_set_common_states_and_clear(cso, ctx, cb);
    371 
    372    ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, NULL);
    373 
    374    /* Fragment shader. */
    375    fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target,
    376                                       TGSI_INTERPOLATE_LINEAR,
    377                                       TGSI_RETURN_TYPE_FLOAT,
    378                                       TGSI_RETURN_TYPE_FLOAT);
    379    cso_set_fragment_shader_handle(cso, fs);
    380 
    381    /* Vertex shader. */
    382    vs = util_set_passthrough_vertex_shader(cso, ctx, false);
    383    util_draw_fullscreen_quad(cso);
    384 
    385    /* Probe pixels. */
    386    pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
    387                                   cb->width0, cb->height0, expected,
    388                                   num_expected);
    389 
    390    /* Cleanup. */
    391    cso_destroy_context(cso);
    392    ctx->delete_vs_state(ctx, vs);
    393    ctx->delete_fs_state(ctx, fs);
    394    pipe_resource_reference(&cb, NULL);
    395 
    396    util_report_result_helper(pass, "%s: %s", __func__,
    397                              tgsi_texture_names[tgsi_tex_target]);
    398 }
    399 
    400 static void
    401 null_constant_buffer(struct pipe_context *ctx)
    402 {
    403    struct cso_context *cso;
    404    struct pipe_resource *cb;
    405    void *fs, *vs;
    406    bool pass = true;
    407    static const float zero[] = {0, 0, 0, 0};
    408 
    409    cso = cso_create_context(ctx);
    410    cb = util_create_texture2d(ctx->screen, 256, 256,
    411                               PIPE_FORMAT_R8G8B8A8_UNORM);
    412    util_set_common_states_and_clear(cso, ctx, cb);
    413 
    414    ctx->set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, NULL);
    415 
    416    /* Fragment shader. */
    417    {
    418       static const char *text = /* I don't like ureg... */
    419             "FRAG\n"
    420             "DCL CONST[0]\n"
    421             "DCL OUT[0], COLOR\n"
    422 
    423             "MOV OUT[0], CONST[0]\n"
    424             "END\n";
    425       struct tgsi_token tokens[1000];
    426       struct pipe_shader_state state;
    427 
    428       if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
    429          puts("Can't compile a fragment shader.");
    430          util_report_result(FAIL);
    431          return;
    432       }
    433       pipe_shader_state_from_tgsi(&state, tokens);
    434       fs = ctx->create_fs_state(ctx, &state);
    435       cso_set_fragment_shader_handle(cso, fs);
    436    }
    437 
    438    /* Vertex shader. */
    439    vs = util_set_passthrough_vertex_shader(cso, ctx, false);
    440    util_draw_fullscreen_quad(cso);
    441 
    442    /* Probe pixels. */
    443    pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0,
    444                                        cb->height0, zero);
    445 
    446    /* Cleanup. */
    447    cso_destroy_context(cso);
    448    ctx->delete_vs_state(ctx, vs);
    449    ctx->delete_fs_state(ctx, fs);
    450    pipe_resource_reference(&cb, NULL);
    451 
    452    util_report_result(pass);
    453 }
    454 
    455 static void
    456 null_fragment_shader(struct pipe_context *ctx)
    457 {
    458    struct cso_context *cso;
    459    struct pipe_resource *cb;
    460    void *vs;
    461    struct pipe_rasterizer_state rs = {0};
    462    struct pipe_query *query;
    463    union pipe_query_result qresult;
    464 
    465    cso = cso_create_context(ctx);
    466    cb = util_create_texture2d(ctx->screen, 256, 256,
    467                               PIPE_FORMAT_R8G8B8A8_UNORM);
    468    util_set_common_states_and_clear(cso, ctx, cb);
    469 
    470    /* No rasterization. */
    471    rs.rasterizer_discard = 1;
    472    cso_set_rasterizer(cso, &rs);
    473 
    474    vs = util_set_passthrough_vertex_shader(cso, ctx, false);
    475 
    476    query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0);
    477    ctx->begin_query(ctx, query);
    478    util_draw_fullscreen_quad(cso);
    479    ctx->end_query(ctx, query);
    480    ctx->get_query_result(ctx, query, true, &qresult);
    481 
    482    /* Cleanup. */
    483    cso_destroy_context(cso);
    484    ctx->delete_vs_state(ctx, vs);
    485    ctx->destroy_query(ctx, query);
    486    pipe_resource_reference(&cb, NULL);
    487 
    488    /* Check PRIMITIVES_GENERATED. */
    489    util_report_result(qresult.u64 == 2);
    490 }
    491 
    492 /**
    493  * Run all tests. This should be run with a clean context after
    494  * context_create.
    495  */
    496 void
    497 util_run_tests(struct pipe_screen *screen)
    498 {
    499    struct pipe_context *ctx = screen->context_create(screen, NULL, 0);
    500 
    501    null_fragment_shader(ctx);
    502    tgsi_vs_window_space_position(ctx);
    503    null_sampler_view(ctx, TGSI_TEXTURE_2D);
    504    null_sampler_view(ctx, TGSI_TEXTURE_BUFFER);
    505    null_constant_buffer(ctx);
    506 
    507    ctx->destroy(ctx);
    508 
    509    puts("Done. Exiting..");
    510    exit(0);
    511 }
    512