graw: new tri-instanced.c program to test instanced drawing
[mesa.git] / src / gallium / tests / graw / tri-instanced.c
1 /*
2 * Test draw instancing.
3 */
4
5 #include "state_tracker/graw.h"
6 #include "pipe/p_screen.h"
7 #include "pipe/p_context.h"
8 #include "pipe/p_state.h"
9 #include "pipe/p_defines.h"
10
11 #include "util/u_debug.h" /* debug_dump_surface_bmp() */
12 #include "util/u_memory.h" /* Offset() */
13
14 enum pipe_format formats[] = {
15 PIPE_FORMAT_R8G8B8A8_UNORM,
16 PIPE_FORMAT_B8G8R8A8_UNORM,
17 PIPE_FORMAT_NONE
18 };
19
20 static const int WIDTH = 300;
21 static const int HEIGHT = 300;
22
23 static struct pipe_screen *screen = NULL;
24 static struct pipe_context *ctx = NULL;
25 static struct pipe_surface *surf = NULL;
26 static void *window = NULL;
27
28 struct vertex {
29 float position[4];
30 float color[4];
31 };
32
33
34 /**
35 * Vertex data.
36 * Each vertex has three attributes: position, color and translation.
37 * The translation attribute is a per-instance attribute. See
38 * "instance_divisor" below.
39 */
40 static struct vertex vertices[4] =
41 {
42 {
43 { 0.0f, -0.3f, 0.0f, 1.0f }, /* pos */
44 { 1.0f, 0.0f, 0.0f, 1.0f } /* color */
45 },
46 {
47 { -0.2f, 0.3f, 0.0f, 1.0f },
48 { 0.0f, 1.0f, 0.0f, 1.0f }
49 },
50 {
51 { 0.2f, 0.3f, 0.0f, 1.0f },
52 { 0.0f, 0.0f, 1.0f, 1.0f }
53 }
54 };
55
56
57 #define NUM_INST 5
58
59 static float inst_data[NUM_INST][4] =
60 {
61 { -0.50f, 0.4f, 0.0f, 0.0f },
62 { -0.25f, 0.1f, 0.0f, 0.0f },
63 { 0.00f, 0.2f, 0.0f, 0.0f },
64 { 0.25f, 0.1f, 0.0f, 0.0f },
65 { 0.50f, 0.3f, 0.0f, 0.0f }
66 };
67
68
69 static void set_viewport( float x, float y,
70 float width, float height,
71 float near, float far)
72 {
73 float z = far;
74 float half_width = (float)width / 2.0f;
75 float half_height = (float)height / 2.0f;
76 float half_depth = ((float)far - (float)near) / 2.0f;
77 struct pipe_viewport_state vp;
78
79 vp.scale[0] = half_width;
80 vp.scale[1] = half_height;
81 vp.scale[2] = half_depth;
82 vp.scale[3] = 1.0f;
83
84 vp.translate[0] = half_width + x;
85 vp.translate[1] = half_height + y;
86 vp.translate[2] = half_depth + z;
87 vp.translate[3] = 0.0f;
88
89 ctx->set_viewport_state( ctx, &vp );
90 }
91
92
93 static void set_vertices( void )
94 {
95 struct pipe_vertex_element ve[3];
96 struct pipe_vertex_buffer vbuf[2];
97 void *handle;
98
99 memset(ve, 0, sizeof ve);
100
101 /* pos */
102 ve[0].src_offset = Offset(struct vertex, position);
103 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
104 ve[0].vertex_buffer_index = 0;
105
106 /* color */
107 ve[1].src_offset = Offset(struct vertex, color);
108 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
109 ve[1].vertex_buffer_index = 0;
110
111 /* per-instance info */
112 ve[2].src_offset = 0;
113 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
114 ve[2].vertex_buffer_index = 1;
115 ve[2].instance_divisor = 1;
116
117 handle = ctx->create_vertex_elements_state(ctx, 3, ve);
118 ctx->bind_vertex_elements_state(ctx, handle);
119
120
121 /* vertex data */
122 vbuf[0].stride = sizeof( struct vertex );
123 vbuf[0].max_index = sizeof(vertices) / vbuf[0].stride;
124 vbuf[0].buffer_offset = 0;
125 vbuf[0].buffer = screen->user_buffer_create(screen,
126 vertices,
127 sizeof(vertices),
128 PIPE_BIND_VERTEX_BUFFER);
129
130 /* instance data */
131 vbuf[1].stride = sizeof( inst_data[0] );
132 vbuf[1].max_index = sizeof(inst_data) / vbuf[1].stride;
133 vbuf[1].buffer_offset = 0;
134 vbuf[1].buffer = screen->user_buffer_create(screen,
135 inst_data,
136 sizeof(inst_data),
137 PIPE_BIND_VERTEX_BUFFER);
138
139
140 ctx->set_vertex_buffers(ctx, 2, vbuf);
141 }
142
143 static void set_vertex_shader( void )
144 {
145 void *handle;
146 const char *text =
147 "VERT\n"
148 "DCL IN[0]\n"
149 "DCL IN[1]\n"
150 "DCL IN[2]\n"
151 "DCL OUT[0], POSITION\n"
152 "DCL OUT[1], COLOR\n"
153 " 0: MOV OUT[1], IN[1]\n"
154 " 1: ADD OUT[0], IN[0], IN[2]\n" /* add instance pos to vertex pos */
155 " 2: END\n";
156
157 handle = graw_parse_vertex_shader(ctx, text);
158 ctx->bind_vs_state(ctx, handle);
159 }
160
161 static void set_fragment_shader( void )
162 {
163 void *handle;
164 const char *text =
165 "FRAG\n"
166 "DCL IN[0], COLOR, LINEAR\n"
167 "DCL OUT[0], COLOR\n"
168 " 0: MOV OUT[0], IN[0]\n"
169 " 1: END\n";
170
171 handle = graw_parse_fragment_shader(ctx, text);
172 ctx->bind_fs_state(ctx, handle);
173 }
174
175
176 static void draw( void )
177 {
178 float clear_color[4] = {1,0,1,1};
179
180 ctx->clear(ctx, PIPE_CLEAR_COLOR, clear_color, 0, 0);
181 /* draw NUM_INST triangles */
182 ctx->draw_arrays_instanced(ctx, PIPE_PRIM_TRIANGLES, 0, 3, 0, NUM_INST);
183 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
184
185 #if 0
186 /* At the moment, libgraw leaks out/makes available some of the
187 * symbols from gallium/auxiliary, including these debug helpers.
188 * Will eventually want to bless some of these paths, and lock the
189 * others down so they aren't accessible from test programs.
190 *
191 * This currently just happens to work on debug builds - a release
192 * build will probably fail to link here:
193 */
194 debug_dump_surface_bmp(ctx, "result.bmp", surf);
195 #endif
196
197 screen->flush_frontbuffer(screen, surf, window);
198 }
199
200
201 static void init( void )
202 {
203 struct pipe_framebuffer_state fb;
204 struct pipe_resource *tex, templat;
205 int i;
206
207 /* It's hard to say whether window or screen should be created
208 * first. Different environments would prefer one or the other.
209 *
210 * Also, no easy way of querying supported formats if the screen
211 * cannot be created first.
212 */
213 for (i = 0;
214 window == NULL && formats[i] != PIPE_FORMAT_NONE;
215 i++) {
216
217 screen = graw_create_window_and_screen(0,0,300,300,
218 formats[i],
219 &window);
220 }
221
222 ctx = screen->context_create(screen, NULL);
223 if (ctx == NULL)
224 exit(3);
225
226 templat.target = PIPE_TEXTURE_2D;
227 templat.format = formats[i];
228 templat.width0 = WIDTH;
229 templat.height0 = HEIGHT;
230 templat.depth0 = 1;
231 templat.last_level = 0;
232 templat.nr_samples = 1;
233 templat.bind = (PIPE_BIND_RENDER_TARGET |
234 PIPE_BIND_DISPLAY_TARGET);
235
236 tex = screen->resource_create(screen,
237 &templat);
238 if (tex == NULL)
239 exit(4);
240
241 surf = screen->get_tex_surface(screen, tex, 0, 0, 0,
242 PIPE_BIND_RENDER_TARGET |
243 PIPE_BIND_DISPLAY_TARGET);
244 if (surf == NULL)
245 exit(5);
246
247 memset(&fb, 0, sizeof fb);
248 fb.nr_cbufs = 1;
249 fb.width = WIDTH;
250 fb.height = HEIGHT;
251 fb.cbufs[0] = surf;
252
253 ctx->set_framebuffer_state(ctx, &fb);
254
255 {
256 struct pipe_blend_state blend;
257 void *handle;
258 memset(&blend, 0, sizeof blend);
259 blend.rt[0].colormask = PIPE_MASK_RGBA;
260 handle = ctx->create_blend_state(ctx, &blend);
261 ctx->bind_blend_state(ctx, handle);
262 }
263
264 {
265 struct pipe_depth_stencil_alpha_state depthstencil;
266 void *handle;
267 memset(&depthstencil, 0, sizeof depthstencil);
268 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
269 ctx->bind_depth_stencil_alpha_state(ctx, handle);
270 }
271
272 {
273 struct pipe_rasterizer_state rasterizer;
274 void *handle;
275 memset(&rasterizer, 0, sizeof rasterizer);
276 rasterizer.cull_face = PIPE_FACE_NONE;
277 rasterizer.gl_rasterization_rules = 1;
278 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
279 ctx->bind_rasterizer_state(ctx, handle);
280 }
281
282 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
283 set_vertices();
284 set_vertex_shader();
285 set_fragment_shader();
286 }
287
288
289 int main( int argc, char *argv[] )
290 {
291 init();
292
293 graw_set_display_func( draw );
294 graw_main_loop();
295 return 0;
296 }