101e04c3fSmrg/************************************************************************** 201e04c3fSmrg * 301e04c3fSmrg * Copyright 2014 Advanced Micro Devices, Inc. 401e04c3fSmrg * All Rights Reserved. 501e04c3fSmrg * 601e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 701e04c3fSmrg * copy of this software and associated documentation files (the 801e04c3fSmrg * "Software"), to deal in the Software without restriction, including 901e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish, 1001e04c3fSmrg * distribute, sub license, and/or sell copies of the Software, and to 1101e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to 1201e04c3fSmrg * the following conditions: 1301e04c3fSmrg * 1401e04c3fSmrg * The above copyright notice and this permission notice (including the 1501e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions 1601e04c3fSmrg * of the Software. 1701e04c3fSmrg * 1801e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1901e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2001e04c3fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2101e04c3fSmrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR 2201e04c3fSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2301e04c3fSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2401e04c3fSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2501e04c3fSmrg * 2601e04c3fSmrg **************************************************************************/ 2701e04c3fSmrg 2801e04c3fSmrg#include "util/u_tests.h" 2901e04c3fSmrg 3001e04c3fSmrg#include "util/u_draw_quad.h" 317ec681f3Smrg#include "util/format/u_format.h" 3201e04c3fSmrg#include "util/u_inlines.h" 3301e04c3fSmrg#include "util/u_memory.h" 3401e04c3fSmrg#include "util/u_simple_shaders.h" 3501e04c3fSmrg#include "util/u_surface.h" 3601e04c3fSmrg#include "util/u_string.h" 3701e04c3fSmrg#include "util/u_tile.h" 3801e04c3fSmrg#include "tgsi/tgsi_strings.h" 3901e04c3fSmrg#include "tgsi/tgsi_text.h" 4001e04c3fSmrg#include "cso_cache/cso_context.h" 417ec681f3Smrg#include "frontend/winsys_handle.h" 4201e04c3fSmrg#include <stdio.h> 4301e04c3fSmrg 4401e04c3fSmrg#define TOLERANCE 0.01 4501e04c3fSmrg 4601e04c3fSmrgstatic struct pipe_resource * 4701e04c3fSmrgutil_create_texture2d(struct pipe_screen *screen, unsigned width, 4801e04c3fSmrg unsigned height, enum pipe_format format, 4901e04c3fSmrg unsigned num_samples) 5001e04c3fSmrg{ 517ec681f3Smrg struct pipe_resource templ = {0}; 5201e04c3fSmrg 5301e04c3fSmrg templ.target = PIPE_TEXTURE_2D; 5401e04c3fSmrg templ.width0 = width; 5501e04c3fSmrg templ.height0 = height; 5601e04c3fSmrg templ.depth0 = 1; 5701e04c3fSmrg templ.array_size = 1; 5801e04c3fSmrg templ.nr_samples = num_samples; 5901e04c3fSmrg templ.nr_storage_samples = num_samples; 6001e04c3fSmrg templ.format = format; 6101e04c3fSmrg templ.usage = PIPE_USAGE_DEFAULT; 6201e04c3fSmrg templ.bind = PIPE_BIND_SAMPLER_VIEW | 6301e04c3fSmrg (util_format_is_depth_or_stencil(format) ? 6401e04c3fSmrg PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET); 6501e04c3fSmrg 6601e04c3fSmrg return screen->resource_create(screen, &templ); 6701e04c3fSmrg} 6801e04c3fSmrg 6901e04c3fSmrgstatic void 7001e04c3fSmrgutil_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx, 7101e04c3fSmrg struct pipe_resource *tex) 7201e04c3fSmrg{ 7301e04c3fSmrg struct pipe_surface templ = {{0}}, *surf; 7401e04c3fSmrg struct pipe_framebuffer_state fb = {0}; 7501e04c3fSmrg 7601e04c3fSmrg templ.format = tex->format; 7701e04c3fSmrg surf = ctx->create_surface(ctx, tex, &templ); 7801e04c3fSmrg 7901e04c3fSmrg fb.width = tex->width0; 8001e04c3fSmrg fb.height = tex->height0; 8101e04c3fSmrg fb.cbufs[0] = surf; 8201e04c3fSmrg fb.nr_cbufs = 1; 8301e04c3fSmrg 8401e04c3fSmrg cso_set_framebuffer(cso, &fb); 8501e04c3fSmrg pipe_surface_reference(&surf, NULL); 8601e04c3fSmrg} 8701e04c3fSmrg 8801e04c3fSmrgstatic void 8901e04c3fSmrgutil_set_blend_normal(struct cso_context *cso) 9001e04c3fSmrg{ 9101e04c3fSmrg struct pipe_blend_state blend = {0}; 9201e04c3fSmrg 9301e04c3fSmrg blend.rt[0].colormask = PIPE_MASK_RGBA; 9401e04c3fSmrg cso_set_blend(cso, &blend); 9501e04c3fSmrg} 9601e04c3fSmrg 9701e04c3fSmrgstatic void 9801e04c3fSmrgutil_set_dsa_disable(struct cso_context *cso) 9901e04c3fSmrg{ 1007ec681f3Smrg struct pipe_depth_stencil_alpha_state dsa = {{{0}}}; 10101e04c3fSmrg 10201e04c3fSmrg cso_set_depth_stencil_alpha(cso, &dsa); 10301e04c3fSmrg} 10401e04c3fSmrg 10501e04c3fSmrgstatic void 10601e04c3fSmrgutil_set_rasterizer_normal(struct cso_context *cso) 10701e04c3fSmrg{ 10801e04c3fSmrg struct pipe_rasterizer_state rs = {0}; 10901e04c3fSmrg 11001e04c3fSmrg rs.half_pixel_center = 1; 11101e04c3fSmrg rs.bottom_edge_rule = 1; 11201e04c3fSmrg rs.depth_clip_near = 1; 11301e04c3fSmrg rs.depth_clip_far = 1; 11401e04c3fSmrg 11501e04c3fSmrg cso_set_rasterizer(cso, &rs); 11601e04c3fSmrg} 11701e04c3fSmrg 11801e04c3fSmrgstatic void 11901e04c3fSmrgutil_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex) 12001e04c3fSmrg{ 12101e04c3fSmrg struct pipe_viewport_state viewport; 12201e04c3fSmrg 12301e04c3fSmrg viewport.scale[0] = 0.5f * tex->width0; 12401e04c3fSmrg viewport.scale[1] = 0.5f * tex->height0; 12501e04c3fSmrg viewport.scale[2] = 1.0f; 12601e04c3fSmrg viewport.translate[0] = 0.5f * tex->width0; 12701e04c3fSmrg viewport.translate[1] = 0.5f * tex->height0; 12801e04c3fSmrg viewport.translate[2] = 0.0f; 1297ec681f3Smrg viewport.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X; 1307ec681f3Smrg viewport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y; 1317ec681f3Smrg viewport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z; 1327ec681f3Smrg viewport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W; 13301e04c3fSmrg 13401e04c3fSmrg cso_set_viewport(cso, &viewport); 13501e04c3fSmrg} 13601e04c3fSmrg 13701e04c3fSmrgstatic void 13801e04c3fSmrgutil_set_interleaved_vertex_elements(struct cso_context *cso, 13901e04c3fSmrg unsigned num_elements) 14001e04c3fSmrg{ 1417ec681f3Smrg struct cso_velems_state velem; 14201e04c3fSmrg unsigned i; 14301e04c3fSmrg 1447ec681f3Smrg memset(&velem, 0, sizeof(velem)); 1457ec681f3Smrg velem.count = num_elements; 14601e04c3fSmrg for (i = 0; i < num_elements; i++) { 1477ec681f3Smrg velem.velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 1487ec681f3Smrg velem.velems[i].src_offset = i * 16; 14901e04c3fSmrg } 15001e04c3fSmrg 1517ec681f3Smrg cso_set_vertex_elements(cso, &velem); 15201e04c3fSmrg} 15301e04c3fSmrg 15401e04c3fSmrgstatic void * 15501e04c3fSmrgutil_set_passthrough_vertex_shader(struct cso_context *cso, 15601e04c3fSmrg struct pipe_context *ctx, 15701e04c3fSmrg bool window_space) 15801e04c3fSmrg{ 15901e04c3fSmrg static const enum tgsi_semantic vs_attribs[] = { 16001e04c3fSmrg TGSI_SEMANTIC_POSITION, 16101e04c3fSmrg TGSI_SEMANTIC_GENERIC 16201e04c3fSmrg }; 16301e04c3fSmrg static const uint vs_indices[] = {0, 0}; 16401e04c3fSmrg void *vs; 16501e04c3fSmrg 16601e04c3fSmrg vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices, 16701e04c3fSmrg window_space); 16801e04c3fSmrg cso_set_vertex_shader_handle(cso, vs); 16901e04c3fSmrg return vs; 17001e04c3fSmrg} 17101e04c3fSmrg 17201e04c3fSmrgstatic void 17301e04c3fSmrgutil_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx, 17401e04c3fSmrg struct pipe_resource *cb) 17501e04c3fSmrg{ 17601e04c3fSmrg static const float clear_color[] = {0.1, 0.1, 0.1, 0.1}; 17701e04c3fSmrg 17801e04c3fSmrg util_set_framebuffer_cb0(cso, ctx, cb); 17901e04c3fSmrg util_set_blend_normal(cso); 18001e04c3fSmrg util_set_dsa_disable(cso); 18101e04c3fSmrg util_set_rasterizer_normal(cso); 18201e04c3fSmrg util_set_max_viewport(cso, cb); 18301e04c3fSmrg 1847ec681f3Smrg ctx->clear(ctx, PIPE_CLEAR_COLOR0, NULL, (void*)clear_color, 0, 0); 18501e04c3fSmrg} 18601e04c3fSmrg 18701e04c3fSmrgstatic void 18801e04c3fSmrgutil_draw_fullscreen_quad(struct cso_context *cso) 18901e04c3fSmrg{ 19001e04c3fSmrg static float vertices[] = { 19101e04c3fSmrg -1, -1, 0, 1, 0, 0, 0, 0, 19201e04c3fSmrg -1, 1, 0, 1, 0, 1, 0, 0, 19301e04c3fSmrg 1, 1, 0, 1, 1, 1, 0, 0, 19401e04c3fSmrg 1, -1, 0, 1, 1, 0, 0, 0 19501e04c3fSmrg }; 19601e04c3fSmrg util_set_interleaved_vertex_elements(cso, 2); 19701e04c3fSmrg util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2); 19801e04c3fSmrg} 19901e04c3fSmrg 20001e04c3fSmrgstatic void 20101e04c3fSmrgutil_draw_fullscreen_quad_fill(struct cso_context *cso, 20201e04c3fSmrg float r, float g, float b, float a) 20301e04c3fSmrg{ 20401e04c3fSmrg float vertices[] = { 20501e04c3fSmrg -1, -1, 0, 1, r, g, b, a, 20601e04c3fSmrg -1, 1, 0, 1, r, g, b, a, 20701e04c3fSmrg 1, 1, 0, 1, r, g, b, a, 20801e04c3fSmrg 1, -1, 0, 1, r, g, b, a, 20901e04c3fSmrg }; 21001e04c3fSmrg util_set_interleaved_vertex_elements(cso, 2); 21101e04c3fSmrg util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2); 21201e04c3fSmrg} 21301e04c3fSmrg 21401e04c3fSmrg/** 21501e04c3fSmrg * Probe and test if the rectangle contains the expected color. 21601e04c3fSmrg * 21701e04c3fSmrg * If "num_expected_colors" > 1, at least one expected color must match 21801e04c3fSmrg * the probed color. "expected" should be an array of 4*num_expected_colors 21901e04c3fSmrg * floats. 22001e04c3fSmrg */ 22101e04c3fSmrgstatic bool 22201e04c3fSmrgutil_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex, 22301e04c3fSmrg unsigned offx, unsigned offy, unsigned w, 22401e04c3fSmrg unsigned h, 22501e04c3fSmrg const float *expected, 22601e04c3fSmrg unsigned num_expected_colors) 22701e04c3fSmrg{ 22801e04c3fSmrg struct pipe_transfer *transfer; 22901e04c3fSmrg void *map; 23001e04c3fSmrg float *pixels = malloc(w * h * 4 * sizeof(float)); 23101e04c3fSmrg unsigned x,y,e,c; 23201e04c3fSmrg bool pass = true; 23301e04c3fSmrg 2347ec681f3Smrg map = pipe_texture_map(ctx, tex, 0, 0, PIPE_MAP_READ, 23501e04c3fSmrg offx, offy, w, h, &transfer); 2367ec681f3Smrg pipe_get_tile_rgba(transfer, map, 0, 0, w, h, tex->format, pixels); 2377ec681f3Smrg pipe_texture_unmap(ctx, transfer); 23801e04c3fSmrg 23901e04c3fSmrg for (e = 0; e < num_expected_colors; e++) { 24001e04c3fSmrg for (y = 0; y < h; y++) { 24101e04c3fSmrg for (x = 0; x < w; x++) { 24201e04c3fSmrg float *probe = &pixels[(y*w + x)*4]; 24301e04c3fSmrg 24401e04c3fSmrg for (c = 0; c < 4; c++) { 24501e04c3fSmrg if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) { 24601e04c3fSmrg if (e < num_expected_colors-1) 24701e04c3fSmrg goto next_color; /* test the next expected color */ 24801e04c3fSmrg 24901e04c3fSmrg printf("Probe color at (%i,%i), ", offx+x, offy+y); 25001e04c3fSmrg printf("Expected: %.3f, %.3f, %.3f, %.3f, ", 25101e04c3fSmrg expected[e*4], expected[e*4+1], 25201e04c3fSmrg expected[e*4+2], expected[e*4+3]); 25301e04c3fSmrg printf("Got: %.3f, %.3f, %.3f, %.3f\n", 25401e04c3fSmrg probe[0], probe[1], probe[2], probe[3]); 25501e04c3fSmrg pass = false; 25601e04c3fSmrg goto done; 25701e04c3fSmrg } 25801e04c3fSmrg } 25901e04c3fSmrg } 26001e04c3fSmrg } 26101e04c3fSmrg break; /* this color was successful */ 26201e04c3fSmrg 26301e04c3fSmrg next_color:; 26401e04c3fSmrg } 26501e04c3fSmrgdone: 26601e04c3fSmrg 26701e04c3fSmrg free(pixels); 26801e04c3fSmrg return pass; 26901e04c3fSmrg} 27001e04c3fSmrg 27101e04c3fSmrgstatic bool 27201e04c3fSmrgutil_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex, 27301e04c3fSmrg unsigned offx, unsigned offy, unsigned w, unsigned h, 27401e04c3fSmrg const float *expected) 27501e04c3fSmrg{ 27601e04c3fSmrg return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1); 27701e04c3fSmrg} 27801e04c3fSmrg 27901e04c3fSmrgenum { 28001e04c3fSmrg SKIP = -1, 28101e04c3fSmrg FAIL = 0, /* also "false" */ 28201e04c3fSmrg PASS = 1 /* also "true" */ 28301e04c3fSmrg}; 28401e04c3fSmrg 28501e04c3fSmrgstatic void 28601e04c3fSmrgutil_report_result_helper(int status, const char *name, ...) 28701e04c3fSmrg{ 28801e04c3fSmrg char buf[256]; 28901e04c3fSmrg va_list ap; 29001e04c3fSmrg 29101e04c3fSmrg va_start(ap, name); 2927ec681f3Smrg vsnprintf(buf, sizeof(buf), name, ap); 29301e04c3fSmrg va_end(ap); 29401e04c3fSmrg 29501e04c3fSmrg printf("Test(%s) = %s\n", buf, 29601e04c3fSmrg status == SKIP ? "skip" : 29701e04c3fSmrg status == PASS ? "pass" : "fail"); 29801e04c3fSmrg} 29901e04c3fSmrg 30001e04c3fSmrg#define util_report_result(status) util_report_result_helper(status, __func__) 30101e04c3fSmrg 30201e04c3fSmrg/** 30301e04c3fSmrg * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION. 30401e04c3fSmrg * 30501e04c3fSmrg * The viewport state is set as usual, but it should have no effect. 30601e04c3fSmrg * Clipping should also be disabled. 30701e04c3fSmrg * 30801e04c3fSmrg * POSITION.xyz should already be multiplied by 1/w and POSITION.w should 30901e04c3fSmrg * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't 31001e04c3fSmrg * multiplied by 1/w (otherwise nothing would be rendered). 31101e04c3fSmrg * 31201e04c3fSmrg * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w 31301e04c3fSmrg * during perspective interpolation is not tested. 31401e04c3fSmrg */ 31501e04c3fSmrgstatic void 31601e04c3fSmrgtgsi_vs_window_space_position(struct pipe_context *ctx) 31701e04c3fSmrg{ 31801e04c3fSmrg struct cso_context *cso; 31901e04c3fSmrg struct pipe_resource *cb; 32001e04c3fSmrg void *fs, *vs; 32101e04c3fSmrg bool pass = true; 32201e04c3fSmrg static const float red[] = {1, 0, 0, 1}; 32301e04c3fSmrg 32401e04c3fSmrg if (!ctx->screen->get_param(ctx->screen, 32501e04c3fSmrg PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) { 32601e04c3fSmrg util_report_result(SKIP); 32701e04c3fSmrg return; 32801e04c3fSmrg } 32901e04c3fSmrg 33001e04c3fSmrg cso = cso_create_context(ctx, 0); 33101e04c3fSmrg cb = util_create_texture2d(ctx->screen, 256, 256, 33201e04c3fSmrg PIPE_FORMAT_R8G8B8A8_UNORM, 0); 33301e04c3fSmrg util_set_common_states_and_clear(cso, ctx, cb); 33401e04c3fSmrg 33501e04c3fSmrg /* Fragment shader. */ 33601e04c3fSmrg fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC, 33701e04c3fSmrg TGSI_INTERPOLATE_LINEAR, TRUE); 33801e04c3fSmrg cso_set_fragment_shader_handle(cso, fs); 33901e04c3fSmrg 34001e04c3fSmrg /* Vertex shader. */ 34101e04c3fSmrg vs = util_set_passthrough_vertex_shader(cso, ctx, true); 34201e04c3fSmrg 34301e04c3fSmrg /* Draw. */ 34401e04c3fSmrg { 34501e04c3fSmrg static float vertices[] = { 34601e04c3fSmrg 0, 0, 0, 0, 1, 0, 0, 1, 34701e04c3fSmrg 0, 256, 0, 0, 1, 0, 0, 1, 34801e04c3fSmrg 256, 256, 0, 0, 1, 0, 0, 1, 34901e04c3fSmrg 256, 0, 0, 0, 1, 0, 0, 1, 35001e04c3fSmrg }; 35101e04c3fSmrg util_set_interleaved_vertex_elements(cso, 2); 35201e04c3fSmrg util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2); 35301e04c3fSmrg } 35401e04c3fSmrg 35501e04c3fSmrg /* Probe pixels. */ 35601e04c3fSmrg pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, 35701e04c3fSmrg cb->width0, cb->height0, red); 35801e04c3fSmrg 35901e04c3fSmrg /* Cleanup. */ 36001e04c3fSmrg cso_destroy_context(cso); 36101e04c3fSmrg ctx->delete_vs_state(ctx, vs); 36201e04c3fSmrg ctx->delete_fs_state(ctx, fs); 36301e04c3fSmrg pipe_resource_reference(&cb, NULL); 36401e04c3fSmrg 36501e04c3fSmrg util_report_result(pass); 36601e04c3fSmrg} 36701e04c3fSmrg 36801e04c3fSmrgstatic void 36901e04c3fSmrgnull_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target) 37001e04c3fSmrg{ 37101e04c3fSmrg struct cso_context *cso; 37201e04c3fSmrg struct pipe_resource *cb; 37301e04c3fSmrg void *fs, *vs; 37401e04c3fSmrg bool pass = true; 37501e04c3fSmrg /* 2 expected colors: */ 37601e04c3fSmrg static const float expected_tex[] = {0, 0, 0, 1, 37701e04c3fSmrg 0, 0, 0, 0}; 37801e04c3fSmrg static const float expected_buf[] = {0, 0, 0, 0}; 37901e04c3fSmrg const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 38001e04c3fSmrg expected_buf : expected_tex; 38101e04c3fSmrg unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2; 38201e04c3fSmrg 38301e04c3fSmrg if (tgsi_tex_target == TGSI_TEXTURE_BUFFER && 38401e04c3fSmrg !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) { 38501e04c3fSmrg util_report_result_helper(SKIP, "%s: %s", __func__, 38601e04c3fSmrg tgsi_texture_names[tgsi_tex_target]); 38701e04c3fSmrg return; 38801e04c3fSmrg } 38901e04c3fSmrg 39001e04c3fSmrg cso = cso_create_context(ctx, 0); 39101e04c3fSmrg cb = util_create_texture2d(ctx->screen, 256, 256, 39201e04c3fSmrg PIPE_FORMAT_R8G8B8A8_UNORM, 0); 39301e04c3fSmrg util_set_common_states_and_clear(cso, ctx, cb); 39401e04c3fSmrg 3957ec681f3Smrg ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0, 1, false, NULL); 39601e04c3fSmrg 39701e04c3fSmrg /* Fragment shader. */ 39801e04c3fSmrg fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target, 39901e04c3fSmrg TGSI_INTERPOLATE_LINEAR, 40001e04c3fSmrg TGSI_RETURN_TYPE_FLOAT, 40101e04c3fSmrg TGSI_RETURN_TYPE_FLOAT, false, false); 40201e04c3fSmrg cso_set_fragment_shader_handle(cso, fs); 40301e04c3fSmrg 40401e04c3fSmrg /* Vertex shader. */ 40501e04c3fSmrg vs = util_set_passthrough_vertex_shader(cso, ctx, false); 40601e04c3fSmrg util_draw_fullscreen_quad(cso); 40701e04c3fSmrg 40801e04c3fSmrg /* Probe pixels. */ 40901e04c3fSmrg pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0, 41001e04c3fSmrg cb->width0, cb->height0, expected, 41101e04c3fSmrg num_expected); 41201e04c3fSmrg 41301e04c3fSmrg /* Cleanup. */ 41401e04c3fSmrg cso_destroy_context(cso); 41501e04c3fSmrg ctx->delete_vs_state(ctx, vs); 41601e04c3fSmrg ctx->delete_fs_state(ctx, fs); 41701e04c3fSmrg pipe_resource_reference(&cb, NULL); 41801e04c3fSmrg 41901e04c3fSmrg util_report_result_helper(pass, "%s: %s", __func__, 42001e04c3fSmrg tgsi_texture_names[tgsi_tex_target]); 42101e04c3fSmrg} 42201e04c3fSmrg 42301e04c3fSmrgvoid 42401e04c3fSmrgutil_test_constant_buffer(struct pipe_context *ctx, 42501e04c3fSmrg struct pipe_resource *constbuf) 42601e04c3fSmrg{ 42701e04c3fSmrg struct cso_context *cso; 42801e04c3fSmrg struct pipe_resource *cb; 42901e04c3fSmrg void *fs, *vs; 43001e04c3fSmrg bool pass = true; 43101e04c3fSmrg static const float zero[] = {0, 0, 0, 0}; 43201e04c3fSmrg 43301e04c3fSmrg cso = cso_create_context(ctx, 0); 43401e04c3fSmrg cb = util_create_texture2d(ctx->screen, 256, 256, 43501e04c3fSmrg PIPE_FORMAT_R8G8B8A8_UNORM, 0); 43601e04c3fSmrg util_set_common_states_and_clear(cso, ctx, cb); 43701e04c3fSmrg 43801e04c3fSmrg pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf); 43901e04c3fSmrg 44001e04c3fSmrg /* Fragment shader. */ 44101e04c3fSmrg { 44201e04c3fSmrg static const char *text = /* I don't like ureg... */ 44301e04c3fSmrg "FRAG\n" 44401e04c3fSmrg "DCL CONST[0][0]\n" 44501e04c3fSmrg "DCL OUT[0], COLOR\n" 44601e04c3fSmrg 44701e04c3fSmrg "MOV OUT[0], CONST[0][0]\n" 44801e04c3fSmrg "END\n"; 44901e04c3fSmrg struct tgsi_token tokens[1000]; 4507ec681f3Smrg struct pipe_shader_state state = {0}; 45101e04c3fSmrg 45201e04c3fSmrg if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { 45301e04c3fSmrg puts("Can't compile a fragment shader."); 45401e04c3fSmrg util_report_result(FAIL); 45501e04c3fSmrg return; 45601e04c3fSmrg } 45701e04c3fSmrg pipe_shader_state_from_tgsi(&state, tokens); 45801e04c3fSmrg fs = ctx->create_fs_state(ctx, &state); 45901e04c3fSmrg cso_set_fragment_shader_handle(cso, fs); 46001e04c3fSmrg } 46101e04c3fSmrg 46201e04c3fSmrg /* Vertex shader. */ 46301e04c3fSmrg vs = util_set_passthrough_vertex_shader(cso, ctx, false); 46401e04c3fSmrg util_draw_fullscreen_quad(cso); 46501e04c3fSmrg 46601e04c3fSmrg /* Probe pixels. */ 46701e04c3fSmrg pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0, 46801e04c3fSmrg cb->height0, zero); 46901e04c3fSmrg 47001e04c3fSmrg /* Cleanup. */ 47101e04c3fSmrg cso_destroy_context(cso); 47201e04c3fSmrg ctx->delete_vs_state(ctx, vs); 47301e04c3fSmrg ctx->delete_fs_state(ctx, fs); 47401e04c3fSmrg pipe_resource_reference(&cb, NULL); 47501e04c3fSmrg 47601e04c3fSmrg util_report_result(pass); 47701e04c3fSmrg} 47801e04c3fSmrg 47901e04c3fSmrgstatic void 4807ec681f3Smrgdisabled_fragment_shader(struct pipe_context *ctx) 48101e04c3fSmrg{ 48201e04c3fSmrg struct cso_context *cso; 48301e04c3fSmrg struct pipe_resource *cb; 48401e04c3fSmrg void *vs; 48501e04c3fSmrg struct pipe_rasterizer_state rs = {0}; 48601e04c3fSmrg struct pipe_query *query; 48701e04c3fSmrg union pipe_query_result qresult; 48801e04c3fSmrg 48901e04c3fSmrg cso = cso_create_context(ctx, 0); 49001e04c3fSmrg cb = util_create_texture2d(ctx->screen, 256, 256, 49101e04c3fSmrg PIPE_FORMAT_R8G8B8A8_UNORM, 0); 49201e04c3fSmrg util_set_common_states_and_clear(cso, ctx, cb); 49301e04c3fSmrg 49401e04c3fSmrg /* No rasterization. */ 49501e04c3fSmrg rs.rasterizer_discard = 1; 49601e04c3fSmrg cso_set_rasterizer(cso, &rs); 49701e04c3fSmrg 49801e04c3fSmrg vs = util_set_passthrough_vertex_shader(cso, ctx, false); 49901e04c3fSmrg 5007ec681f3Smrg void *fs = util_make_empty_fragment_shader(ctx); 5017ec681f3Smrg cso_set_fragment_shader_handle(cso, fs); 5027ec681f3Smrg 50301e04c3fSmrg query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0); 50401e04c3fSmrg ctx->begin_query(ctx, query); 50501e04c3fSmrg util_draw_fullscreen_quad(cso); 50601e04c3fSmrg ctx->end_query(ctx, query); 50701e04c3fSmrg ctx->get_query_result(ctx, query, true, &qresult); 50801e04c3fSmrg 50901e04c3fSmrg /* Cleanup. */ 51001e04c3fSmrg cso_destroy_context(cso); 51101e04c3fSmrg ctx->delete_vs_state(ctx, vs); 5127ec681f3Smrg ctx->delete_fs_state(ctx, fs); 51301e04c3fSmrg ctx->destroy_query(ctx, query); 51401e04c3fSmrg pipe_resource_reference(&cb, NULL); 51501e04c3fSmrg 51601e04c3fSmrg /* Check PRIMITIVES_GENERATED. */ 51701e04c3fSmrg util_report_result(qresult.u64 == 2); 51801e04c3fSmrg} 51901e04c3fSmrg 52001e04c3fSmrg#if defined(PIPE_OS_LINUX) && defined(HAVE_LIBDRM) 52101e04c3fSmrg#include <libsync.h> 52201e04c3fSmrg#else 52301e04c3fSmrg#define sync_merge(str, fd1, fd2) (-1) 52401e04c3fSmrg#define sync_wait(fd, timeout) (-1) 52501e04c3fSmrg#endif 52601e04c3fSmrg 52701e04c3fSmrgstatic void 52801e04c3fSmrgtest_sync_file_fences(struct pipe_context *ctx) 52901e04c3fSmrg{ 53001e04c3fSmrg struct pipe_screen *screen = ctx->screen; 53101e04c3fSmrg bool pass = true; 53201e04c3fSmrg enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC; 53301e04c3fSmrg 53401e04c3fSmrg if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD)) 53501e04c3fSmrg return; 53601e04c3fSmrg 53701e04c3fSmrg struct cso_context *cso = cso_create_context(ctx, 0); 53801e04c3fSmrg struct pipe_resource *buf = 53901e04c3fSmrg pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024); 54001e04c3fSmrg struct pipe_resource *tex = 54101e04c3fSmrg util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0); 54201e04c3fSmrg struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL; 54301e04c3fSmrg 54401e04c3fSmrg /* Run 2 clears, get fencess. */ 54501e04c3fSmrg uint32_t value = 0; 54601e04c3fSmrg ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value)); 54701e04c3fSmrg ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD); 54801e04c3fSmrg 54901e04c3fSmrg struct pipe_box box; 55001e04c3fSmrg u_box_2d(0, 0, tex->width0, tex->height0, &box); 55101e04c3fSmrg ctx->clear_texture(ctx, tex, 0, &box, &value); 55201e04c3fSmrg ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD); 55301e04c3fSmrg pass = pass && buf_fence && tex_fence; 55401e04c3fSmrg 55501e04c3fSmrg /* Export fences. */ 55601e04c3fSmrg int buf_fd = screen->fence_get_fd(screen, buf_fence); 55701e04c3fSmrg int tex_fd = screen->fence_get_fd(screen, tex_fence); 55801e04c3fSmrg pass = pass && buf_fd >= 0 && tex_fd >= 0; 55901e04c3fSmrg 56001e04c3fSmrg /* Merge fences. */ 56101e04c3fSmrg int merged_fd = sync_merge("test", buf_fd, tex_fd); 56201e04c3fSmrg pass = pass && merged_fd >= 0; 56301e04c3fSmrg 56401e04c3fSmrg /* (Re)import all fences. */ 56501e04c3fSmrg struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL; 56601e04c3fSmrg struct pipe_fence_handle *merged_fence = NULL; 56701e04c3fSmrg ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type); 56801e04c3fSmrg ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type); 56901e04c3fSmrg ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type); 57001e04c3fSmrg pass = pass && re_buf_fence && re_tex_fence && merged_fence; 57101e04c3fSmrg 57201e04c3fSmrg /* Run another clear after waiting for everything. */ 57301e04c3fSmrg struct pipe_fence_handle *final_fence = NULL; 57401e04c3fSmrg ctx->fence_server_sync(ctx, merged_fence); 57501e04c3fSmrg value = 0xff; 57601e04c3fSmrg ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value)); 57701e04c3fSmrg ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD); 57801e04c3fSmrg pass = pass && final_fence; 57901e04c3fSmrg 58001e04c3fSmrg /* Wait for the last fence. */ 58101e04c3fSmrg int final_fd = screen->fence_get_fd(screen, final_fence); 58201e04c3fSmrg pass = pass && final_fd >= 0; 58301e04c3fSmrg pass = pass && sync_wait(final_fd, -1) == 0; 58401e04c3fSmrg 58501e04c3fSmrg /* Check that all fences are signalled. */ 58601e04c3fSmrg pass = pass && sync_wait(buf_fd, 0) == 0; 58701e04c3fSmrg pass = pass && sync_wait(tex_fd, 0) == 0; 58801e04c3fSmrg pass = pass && sync_wait(merged_fd, 0) == 0; 58901e04c3fSmrg 59001e04c3fSmrg pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0); 59101e04c3fSmrg pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0); 59201e04c3fSmrg pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0); 59301e04c3fSmrg pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0); 59401e04c3fSmrg pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0); 59501e04c3fSmrg pass = pass && screen->fence_finish(screen, NULL, final_fence, 0); 59601e04c3fSmrg 59701e04c3fSmrg /* Cleanup. */ 59801e04c3fSmrg#ifndef PIPE_OS_WINDOWS 59901e04c3fSmrg if (buf_fd >= 0) 60001e04c3fSmrg close(buf_fd); 60101e04c3fSmrg if (tex_fd >= 0) 60201e04c3fSmrg close(tex_fd); 60301e04c3fSmrg if (merged_fd >= 0) 60401e04c3fSmrg close(merged_fd); 60501e04c3fSmrg if (final_fd >= 0) 60601e04c3fSmrg close(final_fd); 60701e04c3fSmrg#endif 60801e04c3fSmrg 60901e04c3fSmrg screen->fence_reference(screen, &buf_fence, NULL); 61001e04c3fSmrg screen->fence_reference(screen, &tex_fence, NULL); 61101e04c3fSmrg screen->fence_reference(screen, &re_buf_fence, NULL); 61201e04c3fSmrg screen->fence_reference(screen, &re_tex_fence, NULL); 61301e04c3fSmrg screen->fence_reference(screen, &merged_fence, NULL); 61401e04c3fSmrg screen->fence_reference(screen, &final_fence, NULL); 61501e04c3fSmrg 61601e04c3fSmrg cso_destroy_context(cso); 61701e04c3fSmrg pipe_resource_reference(&buf, NULL); 61801e04c3fSmrg pipe_resource_reference(&tex, NULL); 61901e04c3fSmrg 62001e04c3fSmrg util_report_result(pass); 62101e04c3fSmrg} 62201e04c3fSmrg 62301e04c3fSmrgstatic void 62401e04c3fSmrgtest_texture_barrier(struct pipe_context *ctx, bool use_fbfetch, 62501e04c3fSmrg unsigned num_samples) 62601e04c3fSmrg{ 62701e04c3fSmrg struct cso_context *cso; 62801e04c3fSmrg struct pipe_resource *cb; 62901e04c3fSmrg struct pipe_sampler_view *view = NULL; 63001e04c3fSmrg char name[256]; 63101e04c3fSmrg const char *text; 63201e04c3fSmrg 63301e04c3fSmrg assert(num_samples >= 1 && num_samples <= 8); 63401e04c3fSmrg 6357ec681f3Smrg snprintf(name, sizeof(name), "%s: %s, %u samples", __func__, 6367ec681f3Smrg use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1)); 63701e04c3fSmrg 63801e04c3fSmrg if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) { 63901e04c3fSmrg util_report_result_helper(SKIP, name); 64001e04c3fSmrg return; 64101e04c3fSmrg } 64201e04c3fSmrg if (use_fbfetch && 6437ec681f3Smrg !ctx->screen->get_param(ctx->screen, PIPE_CAP_FBFETCH)) { 64401e04c3fSmrg util_report_result_helper(SKIP, name); 64501e04c3fSmrg return; 64601e04c3fSmrg } 64701e04c3fSmrg 64801e04c3fSmrg cso = cso_create_context(ctx, 0); 64901e04c3fSmrg cb = util_create_texture2d(ctx->screen, 256, 256, 65001e04c3fSmrg PIPE_FORMAT_R8G8B8A8_UNORM, num_samples); 65101e04c3fSmrg util_set_common_states_and_clear(cso, ctx, cb); 65201e04c3fSmrg 65301e04c3fSmrg /* Clear each sample to a different value. */ 65401e04c3fSmrg if (num_samples > 1) { 65501e04c3fSmrg void *fs = 65601e04c3fSmrg util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC, 65701e04c3fSmrg TGSI_INTERPOLATE_LINEAR, TRUE); 65801e04c3fSmrg cso_set_fragment_shader_handle(cso, fs); 65901e04c3fSmrg 66001e04c3fSmrg /* Vertex shader. */ 66101e04c3fSmrg void *vs = util_set_passthrough_vertex_shader(cso, ctx, false); 66201e04c3fSmrg 66301e04c3fSmrg for (unsigned i = 0; i < num_samples / 2; i++) { 66401e04c3fSmrg float value; 66501e04c3fSmrg 66601e04c3fSmrg /* 2 consecutive samples should have the same color to test MSAA 66701e04c3fSmrg * compression properly. 66801e04c3fSmrg */ 66901e04c3fSmrg if (num_samples == 2) { 67001e04c3fSmrg value = 0.1; 67101e04c3fSmrg } else { 67201e04c3fSmrg /* The average value must be 0.1 */ 67301e04c3fSmrg static const float values[] = { 67401e04c3fSmrg 0.0, 0.2, 0.05, 0.15 67501e04c3fSmrg }; 67601e04c3fSmrg value = values[i]; 67701e04c3fSmrg } 67801e04c3fSmrg 67901e04c3fSmrg ctx->set_sample_mask(ctx, 0x3 << (i * 2)); 68001e04c3fSmrg util_draw_fullscreen_quad_fill(cso, value, value, value, value); 68101e04c3fSmrg } 68201e04c3fSmrg ctx->set_sample_mask(ctx, ~0); 68301e04c3fSmrg 68401e04c3fSmrg cso_set_vertex_shader_handle(cso, NULL); 68501e04c3fSmrg cso_set_fragment_shader_handle(cso, NULL); 68601e04c3fSmrg ctx->delete_vs_state(ctx, vs); 68701e04c3fSmrg ctx->delete_fs_state(ctx, fs); 68801e04c3fSmrg } 68901e04c3fSmrg 69001e04c3fSmrg if (use_fbfetch) { 69101e04c3fSmrg /* Fragment shader. */ 69201e04c3fSmrg text = "FRAG\n" 69301e04c3fSmrg "DCL OUT[0], COLOR[0]\n" 69401e04c3fSmrg "DCL TEMP[0]\n" 69501e04c3fSmrg "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" 69601e04c3fSmrg 69701e04c3fSmrg "FBFETCH TEMP[0], OUT[0]\n" 69801e04c3fSmrg "ADD OUT[0], TEMP[0], IMM[0]\n" 69901e04c3fSmrg "END\n"; 70001e04c3fSmrg } else { 7017ec681f3Smrg struct pipe_sampler_view templ = {0}; 70201e04c3fSmrg templ.format = cb->format; 70301e04c3fSmrg templ.target = cb->target; 70401e04c3fSmrg templ.swizzle_r = PIPE_SWIZZLE_X; 70501e04c3fSmrg templ.swizzle_g = PIPE_SWIZZLE_Y; 70601e04c3fSmrg templ.swizzle_b = PIPE_SWIZZLE_Z; 70701e04c3fSmrg templ.swizzle_a = PIPE_SWIZZLE_W; 70801e04c3fSmrg view = ctx->create_sampler_view(ctx, cb, &templ); 7097ec681f3Smrg ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, &view); 71001e04c3fSmrg 71101e04c3fSmrg /* Fragment shader. */ 71201e04c3fSmrg if (num_samples > 1) { 71301e04c3fSmrg text = "FRAG\n" 71401e04c3fSmrg "DCL SV[0], POSITION\n" 71501e04c3fSmrg "DCL SV[1], SAMPLEID\n" 71601e04c3fSmrg "DCL SAMP[0]\n" 71701e04c3fSmrg "DCL SVIEW[0], 2D_MSAA, FLOAT\n" 71801e04c3fSmrg "DCL OUT[0], COLOR[0]\n" 71901e04c3fSmrg "DCL TEMP[0]\n" 72001e04c3fSmrg "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" 72101e04c3fSmrg 72201e04c3fSmrg "F2I TEMP[0].xy, SV[0].xyyy\n" 72301e04c3fSmrg "MOV TEMP[0].w, SV[1].xxxx\n" 72401e04c3fSmrg "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n" 72501e04c3fSmrg "ADD OUT[0], TEMP[0], IMM[0]\n" 72601e04c3fSmrg "END\n"; 72701e04c3fSmrg } else { 72801e04c3fSmrg text = "FRAG\n" 72901e04c3fSmrg "DCL SV[0], POSITION\n" 73001e04c3fSmrg "DCL SAMP[0]\n" 73101e04c3fSmrg "DCL SVIEW[0], 2D, FLOAT\n" 73201e04c3fSmrg "DCL OUT[0], COLOR[0]\n" 73301e04c3fSmrg "DCL TEMP[0]\n" 73401e04c3fSmrg "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n" 73501e04c3fSmrg "IMM[1] INT32 { 0, 0, 0, 0}\n" 73601e04c3fSmrg 73701e04c3fSmrg "F2I TEMP[0].xy, SV[0].xyyy\n" 73801e04c3fSmrg "MOV TEMP[0].zw, IMM[1]\n" 73901e04c3fSmrg "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n" 74001e04c3fSmrg "ADD OUT[0], TEMP[0], IMM[0]\n" 74101e04c3fSmrg "END\n"; 74201e04c3fSmrg } 74301e04c3fSmrg } 74401e04c3fSmrg 74501e04c3fSmrg struct tgsi_token tokens[1000]; 7467ec681f3Smrg struct pipe_shader_state state = {0}; 74701e04c3fSmrg 74801e04c3fSmrg if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { 74901e04c3fSmrg assert(0); 75001e04c3fSmrg util_report_result_helper(FAIL, name); 75101e04c3fSmrg return; 75201e04c3fSmrg } 75301e04c3fSmrg pipe_shader_state_from_tgsi(&state, tokens); 75401e04c3fSmrg 75501e04c3fSmrg void *fs = ctx->create_fs_state(ctx, &state); 75601e04c3fSmrg cso_set_fragment_shader_handle(cso, fs); 75701e04c3fSmrg 75801e04c3fSmrg /* Vertex shader. */ 75901e04c3fSmrg void *vs = util_set_passthrough_vertex_shader(cso, ctx, false); 76001e04c3fSmrg 76101e04c3fSmrg if (num_samples > 1 && !use_fbfetch) 76201e04c3fSmrg ctx->set_min_samples(ctx, num_samples); 76301e04c3fSmrg 76401e04c3fSmrg for (int i = 0; i < 2; i++) { 76501e04c3fSmrg ctx->texture_barrier(ctx, 76601e04c3fSmrg use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER : 76701e04c3fSmrg PIPE_TEXTURE_BARRIER_SAMPLER); 76801e04c3fSmrg util_draw_fullscreen_quad(cso); 76901e04c3fSmrg } 77001e04c3fSmrg if (num_samples > 1 && !use_fbfetch) 77101e04c3fSmrg ctx->set_min_samples(ctx, 1); 77201e04c3fSmrg 77301e04c3fSmrg /* Probe pixels. 77401e04c3fSmrg * 77501e04c3fSmrg * For single sample: 77601e04c3fSmrg * result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9) 77701e04c3fSmrg * 77801e04c3fSmrg * For MSAA 4x: 77901e04c3fSmrg * sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8) 78001e04c3fSmrg * sample1 = sample0 78101e04c3fSmrg * sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0) 78201e04c3fSmrg * sample3 = sample2 78301e04c3fSmrg * resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9) 78401e04c3fSmrg */ 78501e04c3fSmrg static const float expected[] = {0.3, 0.5, 0.7, 0.9}; 78601e04c3fSmrg bool pass = util_probe_rect_rgba(ctx, cb, 0, 0, 78701e04c3fSmrg cb->width0, cb->height0, expected); 78801e04c3fSmrg 78901e04c3fSmrg /* Cleanup. */ 79001e04c3fSmrg cso_destroy_context(cso); 79101e04c3fSmrg ctx->delete_vs_state(ctx, vs); 79201e04c3fSmrg ctx->delete_fs_state(ctx, fs); 79301e04c3fSmrg pipe_sampler_view_reference(&view, NULL); 79401e04c3fSmrg pipe_resource_reference(&cb, NULL); 79501e04c3fSmrg 79601e04c3fSmrg util_report_result_helper(pass, name); 79701e04c3fSmrg} 79801e04c3fSmrg 799361fc4cbSmayastatic void 800361fc4cbSmayatest_compute_clear_image(struct pipe_context *ctx) 801361fc4cbSmaya{ 802361fc4cbSmaya struct pipe_resource *cb; 803361fc4cbSmaya const char *text; 804361fc4cbSmaya 805361fc4cbSmaya cb = util_create_texture2d(ctx->screen, 256, 256, 806361fc4cbSmaya PIPE_FORMAT_R8G8B8A8_UNORM, 1); 807361fc4cbSmaya 808361fc4cbSmaya /* Compute shader. */ 809361fc4cbSmaya text = "COMP\n" 810361fc4cbSmaya "PROPERTY CS_FIXED_BLOCK_WIDTH 8\n" 811361fc4cbSmaya "PROPERTY CS_FIXED_BLOCK_HEIGHT 8\n" 812361fc4cbSmaya "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n" 813361fc4cbSmaya "DCL SV[0], THREAD_ID\n" 814361fc4cbSmaya "DCL SV[1], BLOCK_ID\n" 815361fc4cbSmaya "DCL IMAGE[0], 2D, PIPE_FORMAT_R8G8B8A8_UNORM, WR\n" 816361fc4cbSmaya "DCL TEMP[0]\n" 817361fc4cbSmaya "IMM[0] UINT32 { 8, 8, 0, 0}\n" 818361fc4cbSmaya "IMM[1] FLT32 { 1, 0, 0, 0}\n" 819361fc4cbSmaya 820361fc4cbSmaya /* TEMP[0].xy = SV[1] * IMM[0] + SV[0]; */ 821361fc4cbSmaya "UMAD TEMP[0].xy, SV[1], IMM[0], SV[0]\n" 822361fc4cbSmaya "STORE IMAGE[0], TEMP[0], IMM[1], 2D, PIPE_FORMAT_R8G8B8A8_UNORM\n" 823361fc4cbSmaya "END\n"; 824361fc4cbSmaya 825361fc4cbSmaya struct tgsi_token tokens[1000]; 826361fc4cbSmaya if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { 827361fc4cbSmaya assert(0); 828361fc4cbSmaya util_report_result(FAIL); 829361fc4cbSmaya return; 830361fc4cbSmaya } 831361fc4cbSmaya 832361fc4cbSmaya struct pipe_compute_state state = {0}; 833361fc4cbSmaya state.ir_type = PIPE_SHADER_IR_TGSI; 834361fc4cbSmaya state.prog = tokens; 835361fc4cbSmaya 836361fc4cbSmaya void *compute_shader = ctx->create_compute_state(ctx, &state); 837361fc4cbSmaya ctx->bind_compute_state(ctx, compute_shader); 838361fc4cbSmaya 839361fc4cbSmaya /* Bind the image. */ 840361fc4cbSmaya struct pipe_image_view image = {0}; 841361fc4cbSmaya image.resource = cb; 842361fc4cbSmaya image.shader_access = image.access = PIPE_IMAGE_ACCESS_READ_WRITE; 843361fc4cbSmaya image.format = cb->format; 844361fc4cbSmaya 8457ec681f3Smrg ctx->set_shader_images(ctx, PIPE_SHADER_COMPUTE, 0, 1, 0, &image); 846361fc4cbSmaya 847361fc4cbSmaya /* Dispatch compute. */ 848361fc4cbSmaya struct pipe_grid_info info = {0}; 849361fc4cbSmaya info.block[0] = 8; 850361fc4cbSmaya info.block[1] = 8; 851361fc4cbSmaya info.block[2] = 1; 852361fc4cbSmaya info.grid[0] = cb->width0 / 8; 853361fc4cbSmaya info.grid[1] = cb->height0 / 8; 854361fc4cbSmaya info.grid[2] = 1; 855361fc4cbSmaya 856361fc4cbSmaya ctx->launch_grid(ctx, &info); 857361fc4cbSmaya 858361fc4cbSmaya /* Check pixels. */ 859361fc4cbSmaya static const float expected[] = {1.0, 0.0, 0.0, 0.0}; 860361fc4cbSmaya bool pass = util_probe_rect_rgba(ctx, cb, 0, 0, 861361fc4cbSmaya cb->width0, cb->height0, expected); 862361fc4cbSmaya 863361fc4cbSmaya /* Cleanup. */ 864361fc4cbSmaya ctx->delete_compute_state(ctx, compute_shader); 865361fc4cbSmaya pipe_resource_reference(&cb, NULL); 866361fc4cbSmaya 867361fc4cbSmaya util_report_result(pass); 868361fc4cbSmaya} 869361fc4cbSmaya 8707ec681f3Smrg#define NV12_WIDTH 2560 8717ec681f3Smrg#define NV12_HEIGHT 1440 8727ec681f3Smrg 8737ec681f3Smrgstatic bool 8747ec681f3Smrgnv12_validate_resource_fields(struct pipe_resource *tex) 8757ec681f3Smrg{ 8767ec681f3Smrg return tex->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 0) && 8777ec681f3Smrg tex->width0 == NV12_WIDTH && 8787ec681f3Smrg tex->height0 == NV12_HEIGHT && 8797ec681f3Smrg tex->last_level == 0 && 8807ec681f3Smrg tex->usage == PIPE_USAGE_DEFAULT && 8817ec681f3Smrg tex->next && 8827ec681f3Smrg tex->next->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 1) && 8837ec681f3Smrg tex->next->width0 == tex->width0 / 2 && 8847ec681f3Smrg tex->next->height0 == tex->height0 / 2 && 8857ec681f3Smrg tex->next->usage == tex->usage; 8867ec681f3Smrg} 8877ec681f3Smrg 8887ec681f3Smrg/* This test enforces the behavior of NV12 allocation and exports. */ 8897ec681f3Smrgstatic void 8907ec681f3Smrgtest_nv12(struct pipe_screen *screen) 8917ec681f3Smrg{ 8927ec681f3Smrg struct pipe_resource *tex = util_create_texture2d(screen, NV12_WIDTH, NV12_HEIGHT, 8937ec681f3Smrg PIPE_FORMAT_NV12, 1); 8947ec681f3Smrg 8957ec681f3Smrg if (!tex) { 8967ec681f3Smrg printf("resource_create failed\n"); 8977ec681f3Smrg util_report_result(false); 8987ec681f3Smrg return; 8997ec681f3Smrg } 9007ec681f3Smrg 9017ec681f3Smrg if (!nv12_validate_resource_fields(tex)) { 9027ec681f3Smrg printf("incorrect pipe_resource fields\n"); 9037ec681f3Smrg util_report_result(false); 9047ec681f3Smrg return; 9057ec681f3Smrg } 9067ec681f3Smrg 9077ec681f3Smrg /* resource_get_param */ 9087ec681f3Smrg if (screen->resource_get_param) { 9097ec681f3Smrg struct { 9107ec681f3Smrg uint64_t handle, dmabuf, offset, stride, planes; 9117ec681f3Smrg } handle[3]; 9127ec681f3Smrg 9137ec681f3Smrg /* Export */ 9147ec681f3Smrg for (unsigned i = 0; i < 3; i++) { 9157ec681f3Smrg struct pipe_resource *res = i == 2 ? tex->next : tex; 9167ec681f3Smrg unsigned plane = i == 2 ? 0 : i; 9177ec681f3Smrg 9187ec681f3Smrg if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0, 9197ec681f3Smrg PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS, 9207ec681f3Smrg 0, &handle[i].handle)) { 9217ec681f3Smrg printf("resource_get_param failed\n"); 9227ec681f3Smrg util_report_result(false); 9237ec681f3Smrg goto cleanup; 9247ec681f3Smrg } 9257ec681f3Smrg 9267ec681f3Smrg if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0, 9277ec681f3Smrg PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD, 9287ec681f3Smrg 0, &handle[i].dmabuf)) { 9297ec681f3Smrg printf("resource_get_param failed\n"); 9307ec681f3Smrg util_report_result(false); 9317ec681f3Smrg goto cleanup; 9327ec681f3Smrg } 9337ec681f3Smrg 9347ec681f3Smrg if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0, 9357ec681f3Smrg PIPE_RESOURCE_PARAM_OFFSET, 9367ec681f3Smrg 0, &handle[i].offset)) { 9377ec681f3Smrg printf("resource_get_param failed\n"); 9387ec681f3Smrg util_report_result(false); 9397ec681f3Smrg goto cleanup; 9407ec681f3Smrg } 9417ec681f3Smrg 9427ec681f3Smrg if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0, 9437ec681f3Smrg PIPE_RESOURCE_PARAM_STRIDE, 9447ec681f3Smrg 0, &handle[i].stride)) { 9457ec681f3Smrg printf("resource_get_param failed\n"); 9467ec681f3Smrg util_report_result(false); 9477ec681f3Smrg goto cleanup; 9487ec681f3Smrg } 9497ec681f3Smrg 9507ec681f3Smrg if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0, 9517ec681f3Smrg PIPE_RESOURCE_PARAM_NPLANES, 9527ec681f3Smrg 0, &handle[i].planes)) { 9537ec681f3Smrg printf("resource_get_param failed\n"); 9547ec681f3Smrg util_report_result(false); 9557ec681f3Smrg goto cleanup; 9567ec681f3Smrg } 9577ec681f3Smrg } 9587ec681f3Smrg 9597ec681f3Smrg /* Validate export. */ 9607ec681f3Smrg bool get_param_pass = /* Sanity checking */ 9617ec681f3Smrg handle[0].handle && handle[1].handle && handle[2].handle && 9627ec681f3Smrg handle[0].dmabuf && handle[1].dmabuf && handle[2].dmabuf && 9637ec681f3Smrg handle[0].stride && handle[1].stride && handle[2].stride && 9647ec681f3Smrg handle[0].planes == 2 && 9657ec681f3Smrg handle[1].planes == 2 && 9667ec681f3Smrg handle[2].planes == 2 && 9677ec681f3Smrg /* Different planes */ 9687ec681f3Smrg handle[0].handle == handle[1].handle && 9697ec681f3Smrg handle[0].offset != handle[1].offset && 9707ec681f3Smrg /* Same planes. */ 9717ec681f3Smrg handle[1].handle == handle[2].handle && 9727ec681f3Smrg handle[1].stride == handle[2].stride && 9737ec681f3Smrg handle[1].offset == handle[2].offset; 9747ec681f3Smrg 9757ec681f3Smrg if (!get_param_pass) { 9767ec681f3Smrg printf("resource_get_param returned incorrect values\n"); 9777ec681f3Smrg util_report_result(false); 9787ec681f3Smrg goto cleanup; 9797ec681f3Smrg } 9807ec681f3Smrg } 9817ec681f3Smrg 9827ec681f3Smrg /* resource_get_handle */ 9837ec681f3Smrg struct winsys_handle handle[4] = {{0}}; 9847ec681f3Smrg 9857ec681f3Smrg /* Export */ 9867ec681f3Smrg for (unsigned i = 0; i < 4; i++) { 9877ec681f3Smrg handle[i].type = i < 2 ? WINSYS_HANDLE_TYPE_KMS : WINSYS_HANDLE_TYPE_FD; 9887ec681f3Smrg handle[i].plane = i % 2; 9897ec681f3Smrg 9907ec681f3Smrg if (!screen->resource_get_handle(screen, NULL, tex, &handle[i], 0)) { 9917ec681f3Smrg printf("resource_get_handle failed\n"); 9927ec681f3Smrg util_report_result(false); 9937ec681f3Smrg goto cleanup; 9947ec681f3Smrg } 9957ec681f3Smrg } 9967ec681f3Smrg 9977ec681f3Smrg /* Validate export. */ 9987ec681f3Smrg bool get_handle_pass = /* Sanity checking */ 9997ec681f3Smrg handle[0].handle && handle[1].handle && 10007ec681f3Smrg handle[0].stride && handle[1].stride && 10017ec681f3Smrg handle[2].handle && handle[3].handle && 10027ec681f3Smrg handle[2].stride && handle[3].stride && 10037ec681f3Smrg /* KMS - different planes */ 10047ec681f3Smrg handle[0].handle == handle[1].handle && 10057ec681f3Smrg handle[0].offset != handle[1].offset && 10067ec681f3Smrg /* DMABUF - different planes */ 10077ec681f3Smrg handle[2].offset != handle[3].offset && 10087ec681f3Smrg /* KMS and DMABUF equivalence */ 10097ec681f3Smrg handle[0].offset == handle[2].offset && 10107ec681f3Smrg handle[1].offset == handle[3].offset && 10117ec681f3Smrg handle[0].stride == handle[2].stride && 10127ec681f3Smrg handle[1].stride == handle[3].stride; 10137ec681f3Smrg 10147ec681f3Smrg if (!get_handle_pass) { 10157ec681f3Smrg printf("resource_get_handle returned incorrect values\n"); 10167ec681f3Smrg util_report_result(false); 10177ec681f3Smrg goto cleanup; 10187ec681f3Smrg } 10197ec681f3Smrg 10207ec681f3Smrg util_report_result(true); 10217ec681f3Smrg 10227ec681f3Smrgcleanup: 10237ec681f3Smrg pipe_resource_reference(&tex, NULL); 10247ec681f3Smrg} 10257ec681f3Smrg 102601e04c3fSmrg/** 102701e04c3fSmrg * Run all tests. This should be run with a clean context after 102801e04c3fSmrg * context_create. 102901e04c3fSmrg */ 103001e04c3fSmrgvoid 103101e04c3fSmrgutil_run_tests(struct pipe_screen *screen) 103201e04c3fSmrg{ 103301e04c3fSmrg struct pipe_context *ctx = screen->context_create(screen, NULL, 0); 103401e04c3fSmrg 10357ec681f3Smrg disabled_fragment_shader(ctx); 103601e04c3fSmrg tgsi_vs_window_space_position(ctx); 103701e04c3fSmrg null_sampler_view(ctx, TGSI_TEXTURE_2D); 103801e04c3fSmrg null_sampler_view(ctx, TGSI_TEXTURE_BUFFER); 103901e04c3fSmrg util_test_constant_buffer(ctx, NULL); 104001e04c3fSmrg test_sync_file_fences(ctx); 104101e04c3fSmrg 104201e04c3fSmrg for (int i = 1; i <= 8; i = i * 2) 104301e04c3fSmrg test_texture_barrier(ctx, false, i); 104401e04c3fSmrg for (int i = 1; i <= 8; i = i * 2) 104501e04c3fSmrg test_texture_barrier(ctx, true, i); 1046361fc4cbSmaya ctx->destroy(ctx); 104701e04c3fSmrg 1048361fc4cbSmaya ctx = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY); 1049361fc4cbSmaya test_compute_clear_image(ctx); 105001e04c3fSmrg ctx->destroy(ctx); 105101e04c3fSmrg 10527ec681f3Smrg test_nv12(screen); 10537ec681f3Smrg 105401e04c3fSmrg puts("Done. Exiting.."); 105501e04c3fSmrg exit(0); 105601e04c3fSmrg} 1057