gallium/u_tests: test a NULL texture sampler view
[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.translate[0] = 0.5f * tex->width0;
118 viewport.translate[1] = 0.5f * tex->height0;
119 viewport.translate[2] = 0.0f;
120
121 cso_set_viewport(cso, &viewport);
122 }
123
124 static void
125 util_set_interleaved_vertex_elements(struct cso_context *cso,
126 unsigned num_elements)
127 {
128 int i;
129 struct pipe_vertex_element *velem =
130 calloc(1, num_elements * sizeof(struct pipe_vertex_element));
131
132 for (i = 0; i < num_elements; i++) {
133 velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
134 velem[i].src_offset = i * 16;
135 }
136
137 cso_set_vertex_elements(cso, num_elements, velem);
138 free(velem);
139 }
140
141 static void *
142 util_set_passthrough_vertex_shader(struct cso_context *cso,
143 struct pipe_context *ctx,
144 bool window_space)
145 {
146 static const uint vs_attribs[] = {
147 TGSI_SEMANTIC_POSITION,
148 TGSI_SEMANTIC_GENERIC
149 };
150 static const uint vs_indices[] = {0, 0};
151 void *vs;
152
153 vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
154 window_space);
155 cso_set_vertex_shader_handle(cso, vs);
156 return vs;
157 }
158
159 static void
160 util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
161 struct pipe_resource *cb)
162 {
163 static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
164
165 util_set_framebuffer_cb0(cso, ctx, cb);
166 util_set_blend_normal(cso);
167 util_set_dsa_disable(cso);
168 util_set_rasterizer_normal(cso);
169 util_set_max_viewport(cso, cb);
170
171 ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
172 }
173
174 static void
175 util_draw_fullscreen_quad(struct cso_context *cso)
176 {
177 static float vertices[] = {
178 -1, -1, 0, 1, 0, 0, 0, 0,
179 -1, 1, 0, 1, 0, 1, 0, 0,
180 1, 1, 0, 1, 1, 1, 0, 0,
181 1, -1, 0, 1, 1, 0, 0, 0
182 };
183 util_set_interleaved_vertex_elements(cso, 2);
184 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
185 }
186
187 /**
188 * Probe and test if the rectangle contains the expected color.
189 *
190 * If "num_expected_colors" > 1, at least one expected color must match
191 * the probed color. "expected" should be an array of 4*num_expected_colors
192 * floats.
193 */
194 static bool
195 util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
196 unsigned offx, unsigned offy, unsigned w,
197 unsigned h,
198 const float *expected,
199 unsigned num_expected_colors)
200 {
201 struct pipe_transfer *transfer;
202 void *map;
203 float *pixels = malloc(w * h * 4 * sizeof(float));
204 int x,y,e,c;
205 bool pass = true;
206
207 map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
208 offx, offy, w, h, &transfer);
209 pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
210 pipe_transfer_unmap(ctx, transfer);
211
212 for (e = 0; e < num_expected_colors; e++) {
213 for (y = 0; y < h; y++) {
214 for (x = 0; x < w; x++) {
215 float *probe = &pixels[(y*w + x)*4];
216
217 for (c = 0; c < 4; c++) {
218 if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
219 if (e < num_expected_colors-1)
220 goto next_color; /* test the next expected color */
221
222 printf("Probe color at (%i,%i), ", offx+x, offy+y);
223 printf("Expected: %.3f, %.3f, %.3f, %.3f, ",
224 expected[e*4], expected[e*4+1],
225 expected[e*4+2], expected[e*4+3]);
226 printf("Got: %.3f, %.3f, %.3f, %.3f\n",
227 probe[0], probe[1], probe[2], probe[2]);
228 pass = false;
229 goto done;
230 }
231 }
232 }
233 }
234 break; /* this color was successful */
235
236 next_color:;
237 }
238 done:
239
240 free(pixels);
241 return pass;
242 }
243
244 static bool
245 util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
246 unsigned offx, unsigned offy, unsigned w, unsigned h,
247 const float *expected)
248 {
249 return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
250 }
251
252 enum {
253 SKIP = -1,
254 FAIL = 0, /* also "false" */
255 PASS = 1 /* also "true" */
256 };
257
258 static void
259 util_report_result_helper(const char *name, int status)
260 {
261 printf("Test(%s) = %s\n", name,
262 status == SKIP ? "skip" :
263 status == PASS ? "pass" : "fail");
264 }
265
266 #define util_report_result(status) util_report_result_helper(__func__, status)
267
268 /**
269 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
270 *
271 * The viewport state is set as usual, but it should have no effect.
272 * Clipping should also be disabled.
273 *
274 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
275 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
276 * multiplied by 1/w (otherwise nothing would be rendered).
277 *
278 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
279 * during perspective interpolation is not tested.
280 */
281 static void
282 tgsi_vs_window_space_position(struct pipe_context *ctx)
283 {
284 struct cso_context *cso;
285 struct pipe_resource *cb;
286 void *fs, *vs;
287 bool pass = true;
288 static const float red[] = {1, 0, 0, 1};
289
290 if (!ctx->screen->get_param(ctx->screen,
291 PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
292 util_report_result(SKIP);
293 return;
294 }
295
296 cso = cso_create_context(ctx);
297 cb = util_create_texture2d(ctx->screen, 256, 256,
298 PIPE_FORMAT_R8G8B8A8_UNORM);
299 util_set_common_states_and_clear(cso, ctx, cb);
300
301 /* Fragment shader. */
302 fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
303 TGSI_INTERPOLATE_LINEAR, TRUE);
304 cso_set_fragment_shader_handle(cso, fs);
305
306 /* Vertex shader. */
307 vs = util_set_passthrough_vertex_shader(cso, ctx, true);
308
309 /* Draw. */
310 {
311 static float vertices[] = {
312 0, 0, 0, 0, 1, 0, 0, 1,
313 0, 256, 0, 0, 1, 0, 0, 1,
314 256, 256, 0, 0, 1, 0, 0, 1,
315 256, 0, 0, 0, 1, 0, 0, 1,
316 };
317 util_set_interleaved_vertex_elements(cso, 2);
318 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
319 }
320
321 /* Probe pixels. */
322 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
323 cb->width0, cb->height0, red);
324
325 /* Cleanup. */
326 cso_destroy_context(cso);
327 ctx->delete_vs_state(ctx, vs);
328 ctx->delete_fs_state(ctx, fs);
329 pipe_resource_reference(&cb, NULL);
330
331 util_report_result(pass);
332 }
333
334 static void
335 null_sampler_view(struct pipe_context *ctx)
336 {
337 struct cso_context *cso;
338 struct pipe_resource *cb;
339 void *fs, *vs;
340 bool pass = true;
341 /* 2 expected colors: */
342 static const float expected[] = {0, 0, 0, 1,
343 0, 0, 0, 0};
344
345 cso = cso_create_context(ctx);
346 cb = util_create_texture2d(ctx->screen, 256, 256,
347 PIPE_FORMAT_R8G8B8A8_UNORM);
348 util_set_common_states_and_clear(cso, ctx, cb);
349
350 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, NULL);
351
352 /* Fragment shader. */
353 fs = util_make_fragment_tex_shader(ctx, TGSI_TEXTURE_2D,
354 TGSI_INTERPOLATE_LINEAR);
355 cso_set_fragment_shader_handle(cso, fs);
356
357 /* Vertex shader. */
358 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
359 util_draw_fullscreen_quad(cso);
360
361 /* Probe pixels. */
362 pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
363 cb->width0, cb->height0, expected, 2);
364
365 /* Cleanup. */
366 cso_destroy_context(cso);
367 ctx->delete_vs_state(ctx, vs);
368 ctx->delete_fs_state(ctx, fs);
369 pipe_resource_reference(&cb, NULL);
370
371 util_report_result(pass);
372 }
373
374 /**
375 * Run all tests. This should be run with a clean context after
376 * context_create.
377 */
378 void
379 util_run_tests(struct pipe_screen *screen)
380 {
381 struct pipe_context *ctx = screen->context_create(screen, NULL);
382
383 tgsi_vs_window_space_position(ctx);
384 null_sampler_view(ctx);
385
386 ctx->destroy(ctx);
387
388 puts("Done. Exiting..");
389 exit(0);
390 }