5257b548c511ac6eb420559568c1e53c2c1d7bcf
[mesa.git] / src / gallium / auxiliary / util / u_tests.c
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_tile.h"
37 #include "tgsi/tgsi_text.h"
38 #include "cso_cache/cso_context.h"
39 #include <stdio.h>
40
41 #define TOLERANCE 0.01
42
43 static struct pipe_resource *
44 util_create_texture2d(struct pipe_screen *screen, unsigned width,
45 unsigned height, enum pipe_format format)
46 {
47 struct pipe_resource templ = {{0}};
48
49 templ.target = PIPE_TEXTURE_2D;
50 templ.width0 = width;
51 templ.height0 = height;
52 templ.depth0 = 1;
53 templ.array_size = 1;
54 templ.format = format;
55 templ.usage = PIPE_USAGE_DEFAULT;
56 templ.bind = PIPE_BIND_SAMPLER_VIEW |
57 (util_format_is_depth_or_stencil(format) ?
58 PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
59
60 return screen->resource_create(screen, &templ);
61 }
62
63 static void
64 util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
65 struct pipe_resource *tex)
66 {
67 struct pipe_surface templ = {{0}}, *surf;
68 struct pipe_framebuffer_state fb = {0};
69
70 templ.format = tex->format;
71 surf = ctx->create_surface(ctx, tex, &templ);
72
73 fb.width = tex->width0;
74 fb.height = tex->height0;
75 fb.cbufs[0] = surf;
76 fb.nr_cbufs = 1;
77
78 cso_set_framebuffer(cso, &fb);
79 pipe_surface_reference(&surf, NULL);
80 }
81
82 static void
83 util_set_blend_normal(struct cso_context *cso)
84 {
85 struct pipe_blend_state blend = {0};
86
87 blend.rt[0].colormask = PIPE_MASK_RGBA;
88 cso_set_blend(cso, &blend);
89 }
90
91 static void
92 util_set_dsa_disable(struct cso_context *cso)
93 {
94 struct pipe_depth_stencil_alpha_state dsa = {{0}};
95
96 cso_set_depth_stencil_alpha(cso, &dsa);
97 }
98
99 static void
100 util_set_rasterizer_normal(struct cso_context *cso)
101 {
102 struct pipe_rasterizer_state rs = {0};
103
104 rs.half_pixel_center = 1;
105 rs.bottom_edge_rule = 1;
106 rs.depth_clip = 1;
107
108 cso_set_rasterizer(cso, &rs);
109 }
110
111 static void
112 util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
113 {
114 struct pipe_viewport_state viewport;
115
116 viewport.scale[0] = 0.5f * tex->width0;
117 viewport.scale[1] = 0.5f * tex->height0;
118 viewport.scale[2] = 1.0f;
119 viewport.translate[0] = 0.5f * tex->width0;
120 viewport.translate[1] = 0.5f * tex->height0;
121 viewport.translate[2] = 0.0f;
122
123 cso_set_viewport(cso, &viewport);
124 }
125
126 static void
127 util_set_interleaved_vertex_elements(struct cso_context *cso,
128 unsigned num_elements)
129 {
130 int i;
131 struct pipe_vertex_element *velem =
132 calloc(1, num_elements * sizeof(struct pipe_vertex_element));
133
134 for (i = 0; i < num_elements; i++) {
135 velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
136 velem[i].src_offset = i * 16;
137 }
138
139 cso_set_vertex_elements(cso, num_elements, velem);
140 free(velem);
141 }
142
143 static void *
144 util_set_passthrough_vertex_shader(struct cso_context *cso,
145 struct pipe_context *ctx,
146 bool window_space)
147 {
148 static const uint vs_attribs[] = {
149 TGSI_SEMANTIC_POSITION,
150 TGSI_SEMANTIC_GENERIC
151 };
152 static const uint vs_indices[] = {0, 0};
153 void *vs;
154
155 vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
156 window_space);
157 cso_set_vertex_shader_handle(cso, vs);
158 return vs;
159 }
160
161 static void
162 util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
163 struct pipe_resource *cb)
164 {
165 static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
166
167 util_set_framebuffer_cb0(cso, ctx, cb);
168 util_set_blend_normal(cso);
169 util_set_dsa_disable(cso);
170 util_set_rasterizer_normal(cso);
171 util_set_max_viewport(cso, cb);
172
173 ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
174 }
175
176 static void
177 util_draw_fullscreen_quad(struct cso_context *cso)
178 {
179 static float vertices[] = {
180 -1, -1, 0, 1, 0, 0, 0, 0,
181 -1, 1, 0, 1, 0, 1, 0, 0,
182 1, 1, 0, 1, 1, 1, 0, 0,
183 1, -1, 0, 1, 1, 0, 0, 0
184 };
185 util_set_interleaved_vertex_elements(cso, 2);
186 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
187 }
188
189 /**
190 * Probe and test if the rectangle contains the expected color.
191 *
192 * If "num_expected_colors" > 1, at least one expected color must match
193 * the probed color. "expected" should be an array of 4*num_expected_colors
194 * floats.
195 */
196 static bool
197 util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
198 unsigned offx, unsigned offy, unsigned w,
199 unsigned h,
200 const float *expected,
201 unsigned num_expected_colors)
202 {
203 struct pipe_transfer *transfer;
204 void *map;
205 float *pixels = malloc(w * h * 4 * sizeof(float));
206 int x,y,e,c;
207 bool pass = true;
208
209 map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
210 offx, offy, w, h, &transfer);
211 pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
212 pipe_transfer_unmap(ctx, transfer);
213
214 for (e = 0; e < num_expected_colors; e++) {
215 for (y = 0; y < h; y++) {
216 for (x = 0; x < w; x++) {
217 float *probe = &pixels[(y*w + x)*4];
218
219 for (c = 0; c < 4; c++) {
220 if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
221 if (e < num_expected_colors-1)
222 goto next_color; /* test the next expected color */
223
224 printf("Probe color at (%i,%i), ", offx+x, offy+y);
225 printf("Expected: %.3f, %.3f, %.3f, %.3f, ",
226 expected[e*4], expected[e*4+1],
227 expected[e*4+2], expected[e*4+3]);
228 printf("Got: %.3f, %.3f, %.3f, %.3f\n",
229 probe[0], probe[1], probe[2], probe[2]);
230 pass = false;
231 goto done;
232 }
233 }
234 }
235 }
236 break; /* this color was successful */
237
238 next_color:;
239 }
240 done:
241
242 free(pixels);
243 return pass;
244 }
245
246 static bool
247 util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
248 unsigned offx, unsigned offy, unsigned w, unsigned h,
249 const float *expected)
250 {
251 return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
252 }
253
254 enum {
255 SKIP = -1,
256 FAIL = 0, /* also "false" */
257 PASS = 1 /* also "true" */
258 };
259
260 static void
261 util_report_result_helper(const char *name, int status)
262 {
263 printf("Test(%s) = %s\n", name,
264 status == SKIP ? "skip" :
265 status == PASS ? "pass" : "fail");
266 }
267
268 #define util_report_result(status) util_report_result_helper(__func__, status)
269
270 /**
271 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
272 *
273 * The viewport state is set as usual, but it should have no effect.
274 * Clipping should also be disabled.
275 *
276 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
277 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
278 * multiplied by 1/w (otherwise nothing would be rendered).
279 *
280 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
281 * during perspective interpolation is not tested.
282 */
283 static void
284 tgsi_vs_window_space_position(struct pipe_context *ctx)
285 {
286 struct cso_context *cso;
287 struct pipe_resource *cb;
288 void *fs, *vs;
289 bool pass = true;
290 static const float red[] = {1, 0, 0, 1};
291
292 if (!ctx->screen->get_param(ctx->screen,
293 PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
294 util_report_result(SKIP);
295 return;
296 }
297
298 cso = cso_create_context(ctx);
299 cb = util_create_texture2d(ctx->screen, 256, 256,
300 PIPE_FORMAT_R8G8B8A8_UNORM);
301 util_set_common_states_and_clear(cso, ctx, cb);
302
303 /* Fragment shader. */
304 fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
305 TGSI_INTERPOLATE_LINEAR, TRUE);
306 cso_set_fragment_shader_handle(cso, fs);
307
308 /* Vertex shader. */
309 vs = util_set_passthrough_vertex_shader(cso, ctx, true);
310
311 /* Draw. */
312 {
313 static float vertices[] = {
314 0, 0, 0, 0, 1, 0, 0, 1,
315 0, 256, 0, 0, 1, 0, 0, 1,
316 256, 256, 0, 0, 1, 0, 0, 1,
317 256, 0, 0, 0, 1, 0, 0, 1,
318 };
319 util_set_interleaved_vertex_elements(cso, 2);
320 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
321 }
322
323 /* Probe pixels. */
324 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
325 cb->width0, cb->height0, red);
326
327 /* Cleanup. */
328 cso_destroy_context(cso);
329 ctx->delete_vs_state(ctx, vs);
330 ctx->delete_fs_state(ctx, fs);
331 pipe_resource_reference(&cb, NULL);
332
333 util_report_result(pass);
334 }
335
336 static void
337 null_sampler_view(struct pipe_context *ctx)
338 {
339 struct cso_context *cso;
340 struct pipe_resource *cb;
341 void *fs, *vs;
342 bool pass = true;
343 /* 2 expected colors: */
344 static const float expected[] = {0, 0, 0, 1,
345 0, 0, 0, 0};
346
347 cso = cso_create_context(ctx);
348 cb = util_create_texture2d(ctx->screen, 256, 256,
349 PIPE_FORMAT_R8G8B8A8_UNORM);
350 util_set_common_states_and_clear(cso, ctx, cb);
351
352 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, NULL);
353
354 /* Fragment shader. */
355 fs = util_make_fragment_tex_shader(ctx, TGSI_TEXTURE_2D,
356 TGSI_INTERPOLATE_LINEAR);
357 cso_set_fragment_shader_handle(cso, fs);
358
359 /* Vertex shader. */
360 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
361 util_draw_fullscreen_quad(cso);
362
363 /* Probe pixels. */
364 pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
365 cb->width0, cb->height0, expected, 2);
366
367 /* Cleanup. */
368 cso_destroy_context(cso);
369 ctx->delete_vs_state(ctx, vs);
370 ctx->delete_fs_state(ctx, fs);
371 pipe_resource_reference(&cb, NULL);
372
373 util_report_result(pass);
374 }
375
376 static void
377 null_constant_buffer(struct pipe_context *ctx)
378 {
379 struct cso_context *cso;
380 struct pipe_resource *cb;
381 void *fs, *vs;
382 bool pass = true;
383 static const float zero[] = {0, 0, 0, 0};
384
385 cso = cso_create_context(ctx);
386 cb = util_create_texture2d(ctx->screen, 256, 256,
387 PIPE_FORMAT_R8G8B8A8_UNORM);
388 util_set_common_states_and_clear(cso, ctx, cb);
389
390 ctx->set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, NULL);
391
392 /* Fragment shader. */
393 {
394 static const char *text = /* I don't like ureg... */
395 "FRAG\n"
396 "DCL CONST[0]\n"
397 "DCL OUT[0], COLOR\n"
398
399 "MOV OUT[0], CONST[0]\n"
400 "END\n";
401 struct tgsi_token tokens[1000];
402 struct pipe_shader_state state = {tokens};
403
404 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
405 puts("Can't compile a fragment shader.");
406 util_report_result(FAIL);
407 return;
408 }
409 fs = ctx->create_fs_state(ctx, &state);
410 cso_set_fragment_shader_handle(cso, fs);
411 }
412
413 /* Vertex shader. */
414 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
415 util_draw_fullscreen_quad(cso);
416
417 /* Probe pixels. */
418 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0,
419 cb->height0, zero);
420
421 /* Cleanup. */
422 cso_destroy_context(cso);
423 ctx->delete_vs_state(ctx, vs);
424 ctx->delete_fs_state(ctx, fs);
425 pipe_resource_reference(&cb, NULL);
426
427 util_report_result(pass);
428 }
429
430 /**
431 * Run all tests. This should be run with a clean context after
432 * context_create.
433 */
434 void
435 util_run_tests(struct pipe_screen *screen)
436 {
437 struct pipe_context *ctx = screen->context_create(screen, NULL);
438
439 tgsi_vs_window_space_position(ctx);
440 null_sampler_view(ctx);
441 null_constant_buffer(ctx);
442
443 ctx->destroy(ctx);
444
445 puts("Done. Exiting..");
446 exit(0);
447 }