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 45static struct pipe_resource * 46util_create_texture2d(struct pipe_screen *screen, unsigned width, 47 unsigned height, enum pipe_format format, 48 unsigned num_samples) 49{ 50 struct pipe_resource templ = {{0}}; 51 52 templ.target = PIPE_TEXTURE_2D; 53 templ.width0 = width; 54 templ.height0 = height; 55 templ.depth0 = 1; 56 templ.array_size = 1; 57 templ.nr_samples = num_samples; 58 templ.nr_storage_samples = num_samples; 59 templ.format = format; 60 templ.usage = PIPE_USAGE_DEFAULT; 61 templ.bind = PIPE_BIND_SAMPLER_VIEW | 62 (util_format_is_depth_or_stencil(format) ? 63 PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET); 64 65 return screen->resource_create(screen, &templ); 66} 67 68static void 69util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx, 70 struct pipe_resource *tex) 71{ 72 struct pipe_surface templ = {{0}}, *surf; 73 struct pipe_framebuffer_state fb = {0}; 74 75 templ.format = tex->format; 76 surf = ctx->create_surface(ctx, tex, &templ); 77 78 fb.width = tex->width0; 79 fb.height = tex->height0; 80 fb.cbufs[0] = surf; 81 fb.nr_cbufs = 1; 82 83 cso_set_framebuffer(cso, &fb); 84 pipe_surface_reference(&surf, NULL); 85} 86 87static void 88util_set_blend_normal(struct cso_context *cso) 89{ 90 struct pipe_blend_state blend = {0}; 91 92 blend.rt[0].colormask = PIPE_MASK_RGBA; 93 cso_set_blend(cso, &blend); 94} 95 96static void 97util_set_dsa_disable(struct cso_context *cso) 98{ 99 struct pipe_depth_stencil_alpha_state dsa = {{0}}; 100 101 cso_set_depth_stencil_alpha(cso, &dsa); 102} 103 104static void 105util_set_rasterizer_normal(struct cso_context *cso) 106{ 107 struct pipe_rasterizer_state rs = {0}; 108 109 rs.half_pixel_center = 1; 110 rs.bottom_edge_rule = 1; 111 rs.depth_clip_near = 1; 112 rs.depth_clip_far = 1; 113 114 cso_set_rasterizer(cso, &rs); 115} 116 117static void 118util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex) 119{ 120 struct pipe_viewport_state viewport; 121 122 viewport.scale[0] = 0.5f * tex->width0; 123 viewport.scale[1] = 0.5f * tex->height0; 124 viewport.scale[2] = 1.0f; 125 viewport.translate[0] = 0.5f * tex->width0; 126 viewport.translate[1] = 0.5f * tex->height0; 127 viewport.translate[2] = 0.0f; 128 129 cso_set_viewport(cso, &viewport); 130} 131 132static void 133util_set_interleaved_vertex_elements(struct cso_context *cso, 134 unsigned num_elements) 135{ 136 unsigned i; 137 struct pipe_vertex_element *velem = 138 calloc(1, num_elements * sizeof(struct pipe_vertex_element)); 139 140 for (i = 0; i < num_elements; i++) { 141 velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 142 velem[i].src_offset = i * 16; 143 } 144 145 cso_set_vertex_elements(cso, num_elements, velem); 146 free(velem); 147} 148 149static void * 150util_set_passthrough_vertex_shader(struct cso_context *cso, 151 struct pipe_context *ctx, 152 bool window_space) 153{ 154 static const enum tgsi_semantic vs_attribs[] = { 155 TGSI_SEMANTIC_POSITION, 156 TGSI_SEMANTIC_GENERIC 157 }; 158 static const uint vs_indices[] = {0, 0}; 159 void *vs; 160 161 vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices, 162 window_space); 163 cso_set_vertex_shader_handle(cso, vs); 164 return vs; 165} 166 167static void 168util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx, 169 struct pipe_resource *cb) 170{ 171 static const float clear_color[] = {0.1, 0.1, 0.1, 0.1}; 172 173 util_set_framebuffer_cb0(cso, ctx, cb); 174 util_set_blend_normal(cso); 175 util_set_dsa_disable(cso); 176 util_set_rasterizer_normal(cso); 177 util_set_max_viewport(cso, cb); 178 179 ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0); 180} 181 182static void 183util_draw_fullscreen_quad(struct cso_context *cso) 184{ 185 static float vertices[] = { 186 -1, -1, 0, 1, 0, 0, 0, 0, 187 -1, 1, 0, 1, 0, 1, 0, 0, 188 1, 1, 0, 1, 1, 1, 0, 0, 189 1, -1, 0, 1, 1, 0, 0, 0 190 }; 191 util_set_interleaved_vertex_elements(cso, 2); 192 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2); 193} 194 195static void 196util_draw_fullscreen_quad_fill(struct cso_context *cso, 197 float r, float g, float b, float a) 198{ 199 float vertices[] = { 200 -1, -1, 0, 1, r, g, b, a, 201 -1, 1, 0, 1, r, g, b, a, 202 1, 1, 0, 1, r, g, b, a, 203 1, -1, 0, 1, r, g, b, a, 204 }; 205 util_set_interleaved_vertex_elements(cso, 2); 206 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2); 207} 208 209/** 210 * Probe and test if the rectangle contains the expected color. 211 * 212 * If "num_expected_colors" > 1, at least one expected color must match 213 * the probed color. "expected" should be an array of 4*num_expected_colors 214 * floats. 215 */ 216static bool 217util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex, 218 unsigned offx, unsigned offy, unsigned w, 219 unsigned h, 220 const float *expected, 221 unsigned num_expected_colors) 222{ 223 struct pipe_transfer *transfer; 224 void *map; 225 float *pixels = malloc(w * h * 4 * sizeof(float)); 226 unsigned x,y,e,c; 227 bool pass = true; 228 229 map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ, 230 offx, offy, w, h, &transfer); 231 pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels); 232 pipe_transfer_unmap(ctx, transfer); 233 234 for (e = 0; e < num_expected_colors; e++) { 235 for (y = 0; y < h; y++) { 236 for (x = 0; x < w; x++) { 237 float *probe = &pixels[(y*w + x)*4]; 238 239 for (c = 0; c < 4; c++) { 240 if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) { 241 if (e < num_expected_colors-1) 242 goto next_color; /* test the next expected color */ 243 244 printf("Probe color at (%i,%i), ", offx+x, offy+y); 245 printf("Expected: %.3f, %.3f, %.3f, %.3f, ", 246 expected[e*4], expected[e*4+1], 247 expected[e*4+2], expected[e*4+3]); 248 printf("Got: %.3f, %.3f, %.3f, %.3f\n", 249 probe[0], probe[1], probe[2], probe[3]); 250 pass = false; 251 goto done; 252 } 253 } 254 } 255 } 256 break; /* this color was successful */ 257 258 next_color:; 259 } 260done: 261 262 free(pixels); 263 return pass; 264} 265 266static bool 267util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex, 268 unsigned offx, unsigned offy, unsigned w, unsigned h, 269 const float *expected) 270{ 271 return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1); 272} 273 274enum { 275 SKIP = -1, 276 FAIL = 0, /* also "false" */ 277 PASS = 1 /* also "true" */ 278}; 279 280static void 281util_report_result_helper(int status, const char *name, ...) 282{ 283 char buf[256]; 284 va_list ap; 285 286 va_start(ap, name); 287 util_vsnprintf(buf, sizeof(buf), name, ap); 288 va_end(ap); 289 290 printf("Test(%s) = %s\n", buf, 291 status == SKIP ? "skip" : 292 status == PASS ? "pass" : "fail"); 293} 294 295#define util_report_result(status) util_report_result_helper(status, __func__) 296 297/** 298 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION. 299 * 300 * The viewport state is set as usual, but it should have no effect. 301 * Clipping should also be disabled. 302 * 303 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should 304 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't 305 * multiplied by 1/w (otherwise nothing would be rendered). 306 * 307 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w 308 * during perspective interpolation is not tested. 309 */ 310static void 311tgsi_vs_window_space_position(struct pipe_context *ctx) 312{ 313 struct cso_context *cso; 314 struct pipe_resource *cb; 315 void *fs, *vs; 316 bool pass = true; 317 static const float red[] = {1, 0, 0, 1}; 318 319 if (!ctx->screen->get_param(ctx->screen, 320 PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) { 321 util_report_result(SKIP); 322 return; 323 } 324 325 cso = cso_create_context(ctx, 0); 326 cb = util_create_texture2d(ctx->screen, 256, 256, 327 PIPE_FORMAT_R8G8B8A8_UNORM, 0); 328 util_set_common_states_and_clear(cso, ctx, cb); 329 330 /* Fragment shader. */ 331 fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC, 332 TGSI_INTERPOLATE_LINEAR, TRUE); 333 cso_set_fragment_shader_handle(cso, fs); 334 335 /* Vertex shader. */ 336 vs = util_set_passthrough_vertex_shader(cso, ctx, true); 337 338 /* Draw. */ 339 { 340 static float vertices[] = { 341 0, 0, 0, 0, 1, 0, 0, 1, 342 0, 256, 0, 0, 1, 0, 0, 1, 343 256, 256, 0, 0, 1, 0, 0, 1, 344 256, 0, 0, 0, 1, 0, 0, 1, 345 }; 346 util_set_interleaved_vertex_elements(cso, 2); 347 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2); 348 } 349 350 /* Probe pixels. */ 351 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, 352 cb->width0, cb->height0, red); 353 354 /* Cleanup. */ 355 cso_destroy_context(cso); 356 ctx->delete_vs_state(ctx, vs); 357 ctx->delete_fs_state(ctx, fs); 358 pipe_resource_reference(&cb, NULL); 359 360 util_report_result(pass); 361} 362 363static void 364null_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target) 365{ 366 struct cso_context *cso; 367 struct pipe_resource *cb; 368 void *fs, *vs; 369 bool pass = true; 370 /* 2 expected colors: */ 371 static const float expected_tex[] = {0, 0, 0, 1, 372 0, 0, 0, 0}; 373 static const float expected_buf[] = {0, 0, 0, 0}; 374 const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 375 expected_buf : expected_tex; 376 unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2; 377 378 if (tgsi_tex_target == TGSI_TEXTURE_BUFFER && 379 !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) { 380 util_report_result_helper(SKIP, "%s: %s", __func__, 381 tgsi_texture_names[tgsi_tex_target]); 382 return; 383 } 384 385 cso = cso_create_context(ctx, 0); 386 cb = util_create_texture2d(ctx->screen, 256, 256, 387 PIPE_FORMAT_R8G8B8A8_UNORM, 0); 388 util_set_common_states_and_clear(cso, ctx, cb); 389 390 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, NULL); 391 392 /* Fragment shader. */ 393 fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target, 394 TGSI_INTERPOLATE_LINEAR, 395 TGSI_RETURN_TYPE_FLOAT, 396 TGSI_RETURN_TYPE_FLOAT, false, false); 397 cso_set_fragment_shader_handle(cso, fs); 398 399 /* Vertex shader. */ 400 vs = util_set_passthrough_vertex_shader(cso, ctx, false); 401 util_draw_fullscreen_quad(cso); 402 403 /* Probe pixels. */ 404 pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0, 405 cb->width0, cb->height0, expected, 406 num_expected); 407 408 /* Cleanup. */ 409 cso_destroy_context(cso); 410 ctx->delete_vs_state(ctx, vs); 411 ctx->delete_fs_state(ctx, fs); 412 pipe_resource_reference(&cb, NULL); 413 414 util_report_result_helper(pass, "%s: %s", __func__, 415 tgsi_texture_names[tgsi_tex_target]); 416} 417 418void 419util_test_constant_buffer(struct pipe_context *ctx, 420 struct pipe_resource *constbuf) 421{ 422 struct cso_context *cso; 423 struct pipe_resource *cb; 424 void *fs, *vs; 425 bool pass = true; 426 static const float zero[] = {0, 0, 0, 0}; 427 428 cso = cso_create_context(ctx, 0); 429 cb = util_create_texture2d(ctx->screen, 256, 256, 430 PIPE_FORMAT_R8G8B8A8_UNORM, 0); 431 util_set_common_states_and_clear(cso, ctx, cb); 432 433 pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf); 434 435 /* Fragment shader. */ 436 { 437 static const char *text = /* I don't like ureg... */ 438 "FRAG\n" 439 "DCL CONST[0][0]\n" 440 "DCL OUT[0], COLOR\n" 441 442 "MOV OUT[0], CONST[0][0]\n" 443 "END\n"; 444 struct tgsi_token tokens[1000]; 445 struct pipe_shader_state state; 446 447 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { 448 puts("Can't compile a fragment shader."); 449 util_report_result(FAIL); 450 return; 451 } 452 pipe_shader_state_from_tgsi(&state, tokens); 453 fs = ctx->create_fs_state(ctx, &state); 454 cso_set_fragment_shader_handle(cso, fs); 455 } 456 457 /* Vertex shader. */ 458 vs = util_set_passthrough_vertex_shader(cso, ctx, false); 459 util_draw_fullscreen_quad(cso); 460 461 /* Probe pixels. */ 462 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0, 463 cb->height0, zero); 464 465 /* Cleanup. */ 466 cso_destroy_context(cso); 467 ctx->delete_vs_state(ctx, vs); 468 ctx->delete_fs_state(ctx, fs); 469 pipe_resource_reference(&cb, NULL); 470 471 util_report_result(pass); 472} 473 474static void 475null_fragment_shader(struct pipe_context *ctx) 476{ 477 struct cso_context *cso; 478 struct pipe_resource *cb; 479 void *vs; 480 struct pipe_rasterizer_state rs = {0}; 481 struct pipe_query *query; 482 union pipe_query_result qresult; 483 484 cso = cso_create_context(ctx, 0); 485 cb = util_create_texture2d(ctx->screen, 256, 256, 486 PIPE_FORMAT_R8G8B8A8_UNORM, 0); 487 util_set_common_states_and_clear(cso, ctx, cb); 488 489 /* No rasterization. */ 490 rs.rasterizer_discard = 1; 491 cso_set_rasterizer(cso, &rs); 492 493 vs = util_set_passthrough_vertex_shader(cso, ctx, false); 494 495 query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0); 496 ctx->begin_query(ctx, query); 497 util_draw_fullscreen_quad(cso); 498 ctx->end_query(ctx, query); 499 ctx->get_query_result(ctx, query, true, &qresult); 500 501 /* Cleanup. */ 502 cso_destroy_context(cso); 503 ctx->delete_vs_state(ctx, vs); 504 ctx->destroy_query(ctx, query); 505 pipe_resource_reference(&cb, NULL); 506 507 /* Check PRIMITIVES_GENERATED. */ 508 util_report_result(qresult.u64 == 2); 509} 510 511#if defined(PIPE_OS_LINUX) && defined(HAVE_LIBDRM) 512#include <libsync.h> 513#else 514#define sync_merge(str, fd1, fd2) (-1) 515#define sync_wait(fd, timeout) (-1) 516#endif 517 518static void 519test_sync_file_fences(struct pipe_context *ctx) 520{ 521 struct pipe_screen *screen = ctx->screen; 522 bool pass = true; 523 enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC; 524 525 if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD)) 526 return; 527 528 struct cso_context *cso = cso_create_context(ctx, 0); 529 struct pipe_resource *buf = 530 pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024); 531 struct pipe_resource *tex = 532 util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0); 533 struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL; 534 535 /* Run 2 clears, get fencess. */ 536 uint32_t value = 0; 537 ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value)); 538 ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD); 539 540 struct pipe_box box; 541 u_box_2d(0, 0, tex->width0, tex->height0, &box); 542 ctx->clear_texture(ctx, tex, 0, &box, &value); 543 ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD); 544 pass = pass && buf_fence && tex_fence; 545 546 /* Export fences. */ 547 int buf_fd = screen->fence_get_fd(screen, buf_fence); 548 int tex_fd = screen->fence_get_fd(screen, tex_fence); 549 pass = pass && buf_fd >= 0 && tex_fd >= 0; 550 551 /* Merge fences. */ 552 int merged_fd = sync_merge("test", buf_fd, tex_fd); 553 pass = pass && merged_fd >= 0; 554 555 /* (Re)import all fences. */ 556 struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL; 557 struct pipe_fence_handle *merged_fence = NULL; 558 ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type); 559 ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type); 560 ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type); 561 pass = pass && re_buf_fence && re_tex_fence && merged_fence; 562 563 /* Run another clear after waiting for everything. */ 564 struct pipe_fence_handle *final_fence = NULL; 565 ctx->fence_server_sync(ctx, merged_fence); 566 value = 0xff; 567 ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value)); 568 ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD); 569 pass = pass && final_fence; 570 571 /* Wait for the last fence. */ 572 int final_fd = screen->fence_get_fd(screen, final_fence); 573 pass = pass && final_fd >= 0; 574 pass = pass && sync_wait(final_fd, -1) == 0; 575 576 /* Check that all fences are signalled. */ 577 pass = pass && sync_wait(buf_fd, 0) == 0; 578 pass = pass && sync_wait(tex_fd, 0) == 0; 579 pass = pass && sync_wait(merged_fd, 0) == 0; 580 581 pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0); 582 pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0); 583 pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0); 584 pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0); 585 pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0); 586 pass = pass && screen->fence_finish(screen, NULL, final_fence, 0); 587 588 /* Cleanup. */ 589#ifndef PIPE_OS_WINDOWS 590 if (buf_fd >= 0) 591 close(buf_fd); 592 if (tex_fd >= 0) 593 close(tex_fd); 594 if (merged_fd >= 0) 595 close(merged_fd); 596 if (final_fd >= 0) 597 close(final_fd); 598#endif 599 600 screen->fence_reference(screen, &buf_fence, NULL); 601 screen->fence_reference(screen, &tex_fence, NULL); 602 screen->fence_reference(screen, &re_buf_fence, NULL); 603 screen->fence_reference(screen, &re_tex_fence, NULL); 604 screen->fence_reference(screen, &merged_fence, NULL); 605 screen->fence_reference(screen, &final_fence, NULL); 606 607 cso_destroy_context(cso); 608 pipe_resource_reference(&buf, NULL); 609 pipe_resource_reference(&tex, NULL); 610 611 util_report_result(pass); 612} 613 614static void 615test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch, 616 unsigned num_samples) 617{ 618 struct cso_context *cso; 619 struct pipe_resource *cb; 620 struct pipe_sampler_view *view = NULL; 621 char name[256]; 622 const char *text; 623 624 assert(num_samples >= 1 && num_samples <= 8); 625 626 util_snprintf(name, sizeof(name), "%s: %s, %u samples", __func__, 627 use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1)); 628 629 if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) { 630 util_report_result_helper(SKIP, name); 631 return; 632 } 633 if (use_fbfetch && 634 !ctx->screen->get_param(ctx->screen, PIPE_CAP_TGSI_FS_FBFETCH)) { 635 util_report_result_helper(SKIP, name); 636 return; 637 } 638 639 cso = cso_create_context(ctx, 0); 640 cb = util_create_texture2d(ctx->screen, 256, 256, 641 PIPE_FORMAT_R8G8B8A8_UNORM, num_samples); 642 util_set_common_states_and_clear(cso, ctx, cb); 643 644 /* Clear each sample to a different value. */ 645 if (num_samples > 1) { 646 void *fs = 647 util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC, 648 TGSI_INTERPOLATE_LINEAR, TRUE); 649 cso_set_fragment_shader_handle(cso, fs); 650 651 /* Vertex shader. */ 652 void *vs = util_set_passthrough_vertex_shader(cso, ctx, false); 653 654 for (unsigned i = 0; i < num_samples / 2; i++) { 655 float value; 656 657 /* 2 consecutive samples should have the same color to test MSAA 658 * compression properly. 659 */ 660 if (num_samples == 2) { 661 value = 0.1; 662 } else { 663 /* The average value must be 0.1 */ 664 static const float values[] = { 665 0.0, 0.2, 0.05, 0.15 666 }; 667 value = values[i]; 668 } 669 670 ctx->set_sample_mask(ctx, 0x3 << (i * 2)); 671 util_draw_fullscreen_quad_fill(cso, value, value, value, value); 672 } 673 ctx->set_sample_mask(ctx, ~0); 674 675 cso_set_vertex_shader_handle(cso, NULL); 676 cso_set_fragment_shader_handle(cso, NULL); 677 ctx->delete_vs_state(ctx, vs); 678 ctx->delete_fs_state(ctx, fs); 679 } 680 681 if (use_fbfetch) { 682 /* Fragment shader. */ 683 text = "FRAG\n" 684 "DCL OUT[0], COLOR[0]\n" 685 "DCL TEMP[0]\n" 686 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" 687 688 "FBFETCH TEMP[0], OUT[0]\n" 689 "ADD OUT[0], TEMP[0], IMM[0]\n" 690 "END\n"; 691 } else { 692 struct pipe_sampler_view templ = {{0}}; 693 templ.format = cb->format; 694 templ.target = cb->target; 695 templ.swizzle_r = PIPE_SWIZZLE_X; 696 templ.swizzle_g = PIPE_SWIZZLE_Y; 697 templ.swizzle_b = PIPE_SWIZZLE_Z; 698 templ.swizzle_a = PIPE_SWIZZLE_W; 699 view = ctx->create_sampler_view(ctx, cb, &templ); 700 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &view); 701 702 /* Fragment shader. */ 703 if (num_samples > 1) { 704 text = "FRAG\n" 705 "DCL SV[0], POSITION\n" 706 "DCL SV[1], SAMPLEID\n" 707 "DCL SAMP[0]\n" 708 "DCL SVIEW[0], 2D_MSAA, FLOAT\n" 709 "DCL OUT[0], COLOR[0]\n" 710 "DCL TEMP[0]\n" 711 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" 712 713 "F2I TEMP[0].xy, SV[0].xyyy\n" 714 "MOV TEMP[0].w, SV[1].xxxx\n" 715 "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n" 716 "ADD OUT[0], TEMP[0], IMM[0]\n" 717 "END\n"; 718 } else { 719 text = "FRAG\n" 720 "DCL SV[0], POSITION\n" 721 "DCL SAMP[0]\n" 722 "DCL SVIEW[0], 2D, FLOAT\n" 723 "DCL OUT[0], COLOR[0]\n" 724 "DCL TEMP[0]\n" 725 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" 726 "IMM[1] INT32 { 0, 0, 0, 0}\n" 727 728 "F2I TEMP[0].xy, SV[0].xyyy\n" 729 "MOV TEMP[0].zw, IMM[1]\n" 730 "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n" 731 "ADD OUT[0], TEMP[0], IMM[0]\n" 732 "END\n"; 733 } 734 } 735 736 struct tgsi_token tokens[1000]; 737 struct pipe_shader_state state; 738 739 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { 740 assert(0); 741 util_report_result_helper(FAIL, name); 742 return; 743 } 744 pipe_shader_state_from_tgsi(&state, tokens); 745 746 void *fs = ctx->create_fs_state(ctx, &state); 747 cso_set_fragment_shader_handle(cso, fs); 748 749 /* Vertex shader. */ 750 void *vs = util_set_passthrough_vertex_shader(cso, ctx, false); 751 752 if (num_samples > 1 && !use_fbfetch) 753 ctx->set_min_samples(ctx, num_samples); 754 755 for (int i = 0; i < 2; i++) { 756 ctx->texture_barrier(ctx, 757 use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER : 758 PIPE_TEXTURE_BARRIER_SAMPLER); 759 util_draw_fullscreen_quad(cso); 760 } 761 if (num_samples > 1 && !use_fbfetch) 762 ctx->set_min_samples(ctx, 1); 763 764 /* Probe pixels. 765 * 766 * For single sample: 767 * result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9) 768 * 769 * For MSAA 4x: 770 * sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8) 771 * sample1 = sample0 772 * sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0) 773 * sample3 = sample2 774 * resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9) 775 */ 776 static const float expected[] = {0.3, 0.5, 0.7, 0.9}; 777 bool pass = util_probe_rect_rgba(ctx, cb, 0, 0, 778 cb->width0, cb->height0, expected); 779 780 /* Cleanup. */ 781 cso_destroy_context(cso); 782 ctx->delete_vs_state(ctx, vs); 783 ctx->delete_fs_state(ctx, fs); 784 pipe_sampler_view_reference(&view, NULL); 785 pipe_resource_reference(&cb, NULL); 786 787 util_report_result_helper(pass, name); 788} 789 790static void 791test_compute_clear_image(struct pipe_context *ctx) 792{ 793 struct pipe_resource *cb; 794 const char *text; 795 796 cb = util_create_texture2d(ctx->screen, 256, 256, 797 PIPE_FORMAT_R8G8B8A8_UNORM, 1); 798 799 /* Compute shader. */ 800 text = "COMP\n" 801 "PROPERTY CS_FIXED_BLOCK_WIDTH 8\n" 802 "PROPERTY CS_FIXED_BLOCK_HEIGHT 8\n" 803 "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n" 804 "DCL SV[0], THREAD_ID\n" 805 "DCL SV[1], BLOCK_ID\n" 806 "DCL IMAGE[0], 2D, PIPE_FORMAT_R8G8B8A8_UNORM, WR\n" 807 "DCL TEMP[0]\n" 808 "IMM[0] UINT32 { 8, 8, 0, 0}\n" 809 "IMM[1] FLT32 { 1, 0, 0, 0}\n" 810 811 /* TEMP[0].xy = SV[1] * IMM[0] + SV[0]; */ 812 "UMAD TEMP[0].xy, SV[1], IMM[0], SV[0]\n" 813 "STORE IMAGE[0], TEMP[0], IMM[1], 2D, PIPE_FORMAT_R8G8B8A8_UNORM\n" 814 "END\n"; 815 816 struct tgsi_token tokens[1000]; 817 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { 818 assert(0); 819 util_report_result(FAIL); 820 return; 821 } 822 823 struct pipe_compute_state state = {0}; 824 state.ir_type = PIPE_SHADER_IR_TGSI; 825 state.prog = tokens; 826 827 void *compute_shader = ctx->create_compute_state(ctx, &state); 828 ctx->bind_compute_state(ctx, compute_shader); 829 830 /* Bind the image. */ 831 struct pipe_image_view image = {0}; 832 image.resource = cb; 833 image.shader_access = image.access = PIPE_IMAGE_ACCESS_READ_WRITE; 834 image.format = cb->format; 835 836 ctx->set_shader_images(ctx, PIPE_SHADER_COMPUTE, 0, 1, &image); 837 838 /* Dispatch compute. */ 839 struct pipe_grid_info info = {0}; 840 info.block[0] = 8; 841 info.block[1] = 8; 842 info.block[2] = 1; 843 info.grid[0] = cb->width0 / 8; 844 info.grid[1] = cb->height0 / 8; 845 info.grid[2] = 1; 846 847 ctx->launch_grid(ctx, &info); 848 849 /* Check pixels. */ 850 static const float expected[] = {1.0, 0.0, 0.0, 0.0}; 851 bool pass = util_probe_rect_rgba(ctx, cb, 0, 0, 852 cb->width0, cb->height0, expected); 853 854 /* Cleanup. */ 855 ctx->delete_compute_state(ctx, compute_shader); 856 pipe_resource_reference(&cb, NULL); 857 858 util_report_result(pass); 859} 860 861/** 862 * Run all tests. This should be run with a clean context after 863 * context_create. 864 */ 865void 866util_run_tests(struct pipe_screen *screen) 867{ 868 struct pipe_context *ctx = screen->context_create(screen, NULL, 0); 869 870 null_fragment_shader(ctx); 871 tgsi_vs_window_space_position(ctx); 872 null_sampler_view(ctx, TGSI_TEXTURE_2D); 873 null_sampler_view(ctx, TGSI_TEXTURE_BUFFER); 874 util_test_constant_buffer(ctx, NULL); 875 test_sync_file_fences(ctx); 876 877 for (int i = 1; i <= 8; i = i * 2) 878 test_texture_barrier(ctx, false, i); 879 for (int i = 1; i <= 8; i = i * 2) 880 test_texture_barrier(ctx, true, i); 881 ctx->destroy(ctx); 882 883 ctx = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY); 884 test_compute_clear_image(ctx); 885 ctx->destroy(ctx); 886 887 puts("Done. Exiting.."); 888 exit(0); 889} 890