• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
util_create_texture2d(struct pipe_screen * screen,unsigned width,unsigned height,enum pipe_format format)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
util_set_framebuffer_cb0(struct cso_context * cso,struct pipe_context * ctx,struct pipe_resource * tex)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
util_set_blend_normal(struct cso_context * cso)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
util_set_dsa_disable(struct cso_context * cso)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
util_set_rasterizer_normal(struct cso_context * cso)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
util_set_max_viewport(struct cso_context * cso,struct pipe_resource * tex)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
util_set_interleaved_vertex_elements(struct cso_context * cso,unsigned num_elements)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 *
util_set_passthrough_vertex_shader(struct cso_context * cso,struct pipe_context * ctx,bool window_space)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
util_set_common_states_and_clear(struct cso_context * cso,struct pipe_context * ctx,struct pipe_resource * cb)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
util_draw_fullscreen_quad(struct cso_context * cso)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
util_probe_rect_rgba_multi(struct pipe_context * ctx,struct pipe_resource * tex,unsigned offx,unsigned offy,unsigned w,unsigned h,const float * expected,unsigned num_expected_colors)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
util_probe_rect_rgba(struct pipe_context * ctx,struct pipe_resource * tex,unsigned offx,unsigned offy,unsigned w,unsigned h,const float * expected)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
util_report_result_helper(int status,const char * name,...)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
tgsi_vs_window_space_position(struct pipe_context * ctx)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
null_sampler_view(struct pipe_context * ctx,unsigned tgsi_tex_target)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
null_constant_buffer(struct pipe_context * ctx)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
null_fragment_shader(struct pipe_context * ctx)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
util_run_tests(struct pipe_screen * screen)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