gallium/util: add a test for TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION
[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_simple_shaders.h"
34 #include "util/u_surface.h"
35 #include "util/u_tile.h"
36 #include "cso_cache/cso_context.h"
37 #include <stdio.h>
38
39 #define TOLERANCE 0.01
40
41 static struct pipe_resource *
42 util_create_texture2d(struct pipe_screen *screen, unsigned width,
43 unsigned height, enum pipe_format format)
44 {
45 struct pipe_resource templ = {{0}};
46
47 templ.target = PIPE_TEXTURE_2D;
48 templ.width0 = width;
49 templ.height0 = height;
50 templ.depth0 = 1;
51 templ.array_size = 1;
52 templ.format = format;
53 templ.usage = PIPE_USAGE_DEFAULT;
54 templ.bind = PIPE_BIND_SAMPLER_VIEW |
55 (util_format_is_depth_or_stencil(format) ?
56 PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
57
58 return screen->resource_create(screen, &templ);
59 }
60
61 static void
62 util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
63 struct pipe_resource *tex)
64 {
65 struct pipe_surface templ = {{0}}, *surf;
66 struct pipe_framebuffer_state fb = {0};
67
68 templ.format = tex->format;
69 surf = ctx->create_surface(ctx, tex, &templ);
70
71 fb.width = tex->width0;
72 fb.height = tex->height0;
73 fb.cbufs[0] = surf;
74 fb.nr_cbufs = 1;
75
76 cso_set_framebuffer(cso, &fb);
77 pipe_surface_reference(&surf, NULL);
78 }
79
80 static void
81 util_set_blend_normal(struct cso_context *cso)
82 {
83 struct pipe_blend_state blend = {0};
84
85 blend.rt[0].colormask = PIPE_MASK_RGBA;
86 cso_set_blend(cso, &blend);
87 }
88
89 static void
90 util_set_dsa_disable(struct cso_context *cso)
91 {
92 struct pipe_depth_stencil_alpha_state dsa = {{0}};
93
94 cso_set_depth_stencil_alpha(cso, &dsa);
95 }
96
97 static void
98 util_set_rasterizer_normal(struct cso_context *cso)
99 {
100 struct pipe_rasterizer_state rs = {0};
101
102 rs.half_pixel_center = 1;
103 rs.bottom_edge_rule = 1;
104 rs.depth_clip = 1;
105
106 cso_set_rasterizer(cso, &rs);
107 }
108
109 static void
110 util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
111 {
112 struct pipe_viewport_state viewport;
113
114 viewport.scale[0] = 0.5f * tex->width0;
115 viewport.scale[1] = 0.5f * tex->height0;
116 viewport.scale[2] = 1.0f;
117 viewport.scale[3] = 1.0f;
118 viewport.translate[0] = 0.5f * tex->width0;
119 viewport.translate[1] = 0.5f * tex->height0;
120 viewport.translate[2] = 0.0f;
121 viewport.translate[3] = 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 bool
144 util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
145 unsigned offx, unsigned offy, unsigned w, unsigned h,
146 const float *expected)
147 {
148 struct pipe_transfer *transfer;
149 void *map;
150 float *pixels = malloc(w * h * 4 * sizeof(float));
151 int x,y,c;
152 bool pass = true;
153
154 map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
155 offx, offy, w, h, &transfer);
156 pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
157 pipe_transfer_unmap(ctx, transfer);
158
159 for (y = 0; y < h; y++) {
160 for (x = 0; x < w; x++) {
161 float *probe = &pixels[(y*w + x)*4];
162
163 for (c = 0; c < 4; c++)
164 if (fabs(probe[c] - expected[c]) >= TOLERANCE) {
165 printf("Probe color at (%i,%i), ", offx+x, offy+y);
166 printf("Expected: %.3f, %.3f, %.3f, %.3f, ",
167 expected[0], expected[1], expected[2], expected[3]);
168 printf("Got: %.3f, %.3f, %.3f, %.3f\n",
169 probe[0], probe[1], probe[2], probe[2]);
170 pass = false;
171 goto done;
172 }
173 }
174 }
175 done:
176
177 free(pixels);
178 return pass;
179 }
180
181 /**
182 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
183 *
184 * The viewport state is set as usual, but it should have no effect.
185 * Clipping should also be disabled.
186 *
187 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
188 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
189 * multiplied by 1/w (otherwise nothing would be rendered).
190 *
191 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
192 * during perspective interpolation is not tested.
193 */
194 static void
195 tgsi_vs_window_space_position(struct pipe_context *ctx)
196 {
197 struct cso_context *cso;
198 struct pipe_resource *cb;
199 void *fs, *vs;
200 bool pass = true;
201
202 static uint vs_attribs[] = {
203 TGSI_SEMANTIC_POSITION,
204 TGSI_SEMANTIC_GENERIC
205 };
206 static uint vs_indices[] = {0, 0};
207 static float vertices[] = {
208 0, 0, 0, 0, 1, 0, 0, 1,
209 0, 256, 0, 0, 1, 0, 0, 1,
210 256, 256, 0, 0, 1, 0, 0, 1,
211 256, 0, 0, 0, 1, 0, 0, 1,
212 };
213 static float red[] = {1, 0, 0, 1};
214 static float clear_color[] = {0.1, 0.1, 0.1, 0.1};
215
216 if (!ctx->screen->get_param(ctx->screen,
217 PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
218 printf("Test(%s) = skip\n", __func__);
219 return;
220 }
221
222 cso = cso_create_context(ctx);
223 cb = util_create_texture2d(ctx->screen, 256, 256,
224 PIPE_FORMAT_R8G8B8A8_UNORM);
225
226 /* Set states. */
227 util_set_framebuffer_cb0(cso, ctx, cb);
228 util_set_blend_normal(cso);
229 util_set_dsa_disable(cso);
230 util_set_rasterizer_normal(cso);
231 util_set_max_viewport(cso, cb);
232 util_set_interleaved_vertex_elements(cso, 2);
233
234 /* Fragment shader. */
235 fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
236 TGSI_INTERPOLATE_LINEAR, TRUE);
237 cso_set_fragment_shader_handle(cso, fs);
238
239 /* Vertex shader. */
240 vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
241 TRUE);
242 cso_set_vertex_shader_handle(cso, vs);
243
244 /* Clear and draw. */
245 ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
246 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
247
248 /* Probe pixels. */
249 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
250 cb->width0, cb->height0, red);
251
252 /* Cleanup. */
253 cso_release_all(cso);
254 cso_destroy_context(cso);
255 ctx->delete_vs_state(ctx, vs);
256 ctx->delete_fs_state(ctx, fs);
257 pipe_resource_reference(&cb, NULL);
258
259 printf("Test(%s) = %s\n", __func__, pass ? "pass" : "fail");
260 }
261
262 /**
263 * Run all tests. This should be run with a clean context after
264 * context_create.
265 */
266 void
267 util_run_tests(struct pipe_context *ctx)
268 {
269 tgsi_vs_window_space_position(ctx);
270 }