tri-instanced.c revision b8e80941
1/*
2 * Test draw instancing.
3 */
4
5#include <stdio.h>
6#include <string.h>
7
8#include "state_tracker/graw.h"
9#include "pipe/p_screen.h"
10#include "pipe/p_context.h"
11#include "pipe/p_state.h"
12#include "pipe/p_defines.h"
13
14#include "util/u_memory.h"      /* Offset() */
15#include "util/u_draw_quad.h"
16#include "util/u_inlines.h"
17
18
19enum pipe_format formats[] = {
20   PIPE_FORMAT_RGBA8888_UNORM,
21   PIPE_FORMAT_BGRA8888_UNORM,
22   PIPE_FORMAT_NONE
23};
24
25static const int WIDTH = 300;
26static const int HEIGHT = 300;
27
28static struct pipe_screen *screen = NULL;
29static struct pipe_context *ctx = NULL;
30static struct pipe_surface *surf = NULL;
31static struct pipe_resource *tex = NULL;
32static void *window = NULL;
33
34struct vertex {
35   float position[4];
36   float color[4];
37};
38
39
40static int draw_elements = 0;
41
42
43/**
44 * Vertex data.
45 * Each vertex has three attributes: position, color and translation.
46 * The translation attribute is a per-instance attribute.  See
47 * "instance_divisor" below.
48 */
49static struct vertex vertices[4] =
50{
51   {
52      { 0.0f, -0.3f, 0.0f, 1.0f },  /* pos */
53      { 1.0f, 0.0f, 0.0f, 1.0f }    /* color */
54   },
55   {
56      { -0.2f, 0.3f, 0.0f, 1.0f },
57      { 0.0f, 1.0f, 0.0f, 1.0f }
58   },
59   {
60      { 0.2f, 0.3f, 0.0f, 1.0f },
61      { 0.0f, 0.0f, 1.0f, 1.0f }
62   }
63};
64
65
66#define NUM_INST 5
67
68static float inst_data[NUM_INST][4] =
69{
70   { -0.50f, 0.4f, 0.0f, 0.0f },
71   { -0.25f, 0.1f, 0.0f, 0.0f },
72   { 0.00f, 0.2f, 0.0f, 0.0f },
73   { 0.25f, 0.1f, 0.0f, 0.0f },
74   { 0.50f, 0.3f, 0.0f, 0.0f }
75};
76
77
78static ushort indices[3] = { 0, 2, 1 };
79
80
81static void set_viewport( float x, float y,
82                          float width, float height,
83                          float zNear, float zFar)
84{
85   float z = zFar;
86   float half_width = (float)width / 2.0f;
87   float half_height = (float)height / 2.0f;
88   float half_depth = ((float)zFar - (float)zNear) / 2.0f;
89   struct pipe_viewport_state vp;
90
91   vp.scale[0] = half_width;
92   vp.scale[1] = half_height;
93   vp.scale[2] = half_depth;
94
95   vp.translate[0] = half_width + x;
96   vp.translate[1] = half_height + y;
97   vp.translate[2] = half_depth + z;
98
99   ctx->set_viewport_states( ctx, 0, 1, &vp );
100}
101
102
103static void set_vertices( void )
104{
105   struct pipe_vertex_element ve[3];
106   struct pipe_vertex_buffer vbuf[2];
107   void *handle;
108
109   memset(ve, 0, sizeof ve);
110
111   /* pos */
112   ve[0].src_offset = Offset(struct vertex, position);
113   ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
114   ve[0].vertex_buffer_index = 0;
115
116   /* color */
117   ve[1].src_offset = Offset(struct vertex, color);
118   ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
119   ve[1].vertex_buffer_index = 0;
120
121   /* per-instance info */
122   ve[2].src_offset = 0;
123   ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
124   ve[2].vertex_buffer_index = 1;
125   ve[2].instance_divisor = 1;
126
127   handle = ctx->create_vertex_elements_state(ctx, 3, ve);
128   ctx->bind_vertex_elements_state(ctx, handle);
129
130   memset(&vbuf, 0, sizeof vbuf);
131
132   /* vertex data */
133   vbuf[0].stride = sizeof( struct vertex );
134   vbuf[0].buffer_offset = 0;
135   vbuf[0].buffer.resource = pipe_buffer_create_with_data(ctx,
136                                                 PIPE_BIND_VERTEX_BUFFER,
137                                                 PIPE_USAGE_DEFAULT,
138                                                 sizeof(vertices),
139                                                 vertices);
140
141   /* instance data */
142   vbuf[1].stride = sizeof( inst_data[0] );
143   vbuf[1].buffer_offset = 0;
144   vbuf[1].buffer.resource = pipe_buffer_create_with_data(ctx,
145                                                 PIPE_BIND_VERTEX_BUFFER,
146                                                 PIPE_USAGE_DEFAULT,
147                                                 sizeof(inst_data),
148                                                 inst_data);
149
150   ctx->set_vertex_buffers(ctx, 0, 2, vbuf);
151}
152
153static void set_vertex_shader( void )
154{
155   void *handle;
156   const char *text =
157      "VERT\n"
158      "DCL IN[0]\n"
159      "DCL IN[1]\n"
160      "DCL IN[2]\n"
161      "DCL OUT[0], POSITION\n"
162      "DCL OUT[1], COLOR\n"
163      "  0: MOV OUT[1], IN[1]\n"
164      "  1: ADD OUT[0], IN[0], IN[2]\n"  /* add instance pos to vertex pos */
165      "  2: END\n";
166
167   handle = graw_parse_vertex_shader(ctx, text);
168   ctx->bind_vs_state(ctx, handle);
169}
170
171static void set_fragment_shader( void )
172{
173   void *handle;
174   const char *text =
175      "FRAG\n"
176      "DCL IN[0], COLOR, LINEAR\n"
177      "DCL OUT[0], COLOR\n"
178      "  0: MOV OUT[0], IN[0]\n"
179      "  1: END\n";
180
181   handle = graw_parse_fragment_shader(ctx, text);
182   ctx->bind_fs_state(ctx, handle);
183}
184
185
186static void draw( void )
187{
188   union pipe_color_union clear_color = { {1,0,1,1} };
189   struct pipe_draw_info info;
190
191   ctx->clear(ctx, PIPE_CLEAR_COLOR, &clear_color, 0, 0);
192
193
194   util_draw_init_info(&info);
195   info.index_size = draw_elements ? 2 : 0;
196   info.mode = PIPE_PRIM_TRIANGLES;
197   info.start = 0;
198   info.count = 3;
199   /* draw NUM_INST triangles */
200   info.instance_count = NUM_INST;
201
202   /* index data */
203   if (info.index_size) {
204      info.index.resource =
205         pipe_buffer_create_with_data(ctx,
206                                      PIPE_BIND_INDEX_BUFFER,
207                                      PIPE_USAGE_DEFAULT,
208                                      sizeof(indices),
209                                      indices);
210   }
211
212   ctx->draw_vbo(ctx, &info);
213
214   pipe_resource_reference(&info.index.resource, NULL);
215
216   ctx->flush(ctx, NULL, 0);
217
218   graw_save_surface_to_file(ctx, surf, NULL);
219
220   screen->flush_frontbuffer(screen, tex, 0, 0, window, NULL);
221}
222
223
224static void init( void )
225{
226   struct pipe_framebuffer_state fb;
227   struct pipe_resource templat;
228   struct pipe_surface surf_tmpl;
229   int i;
230
231   /* It's hard to say whether window or screen should be created
232    * first.  Different environments would prefer one or the other.
233    *
234    * Also, no easy way of querying supported formats if the screen
235    * cannot be created first.
236    */
237   for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) {
238      screen = graw_create_window_and_screen(0, 0, 300, 300,
239                                             formats[i],
240                                             &window);
241      if (window && screen)
242         break;
243   }
244   if (!screen || !window) {
245      fprintf(stderr, "Unable to create window\n");
246      exit(1);
247   }
248
249   ctx = screen->context_create(screen, NULL, 0);
250   if (ctx == NULL)
251      exit(3);
252
253   memset(&templat, 0, sizeof(templat));
254   templat.target = PIPE_TEXTURE_2D;
255   templat.format = formats[i];
256   templat.width0 = WIDTH;
257   templat.height0 = HEIGHT;
258   templat.depth0 = 1;
259   templat.array_size = 1;
260   templat.last_level = 0;
261   templat.bind = (PIPE_BIND_RENDER_TARGET |
262                   PIPE_BIND_DISPLAY_TARGET);
263
264   tex = screen->resource_create(screen,
265                                 &templat);
266   if (tex == NULL)
267      exit(4);
268
269   surf_tmpl.format = templat.format;
270   surf_tmpl.u.tex.level = 0;
271   surf_tmpl.u.tex.first_layer = 0;
272   surf_tmpl.u.tex.last_layer = 0;
273   surf = ctx->create_surface(ctx, tex, &surf_tmpl);
274   if (surf == NULL)
275      exit(5);
276
277   memset(&fb, 0, sizeof fb);
278   fb.nr_cbufs = 1;
279   fb.width = WIDTH;
280   fb.height = HEIGHT;
281   fb.cbufs[0] = surf;
282
283   ctx->set_framebuffer_state(ctx, &fb);
284
285   {
286      struct pipe_blend_state blend;
287      void *handle;
288      memset(&blend, 0, sizeof blend);
289      blend.rt[0].colormask = PIPE_MASK_RGBA;
290      handle = ctx->create_blend_state(ctx, &blend);
291      ctx->bind_blend_state(ctx, handle);
292   }
293
294   {
295      struct pipe_depth_stencil_alpha_state depthstencil;
296      void *handle;
297      memset(&depthstencil, 0, sizeof depthstencil);
298      handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
299      ctx->bind_depth_stencil_alpha_state(ctx, handle);
300   }
301
302   {
303      struct pipe_rasterizer_state rasterizer;
304      void *handle;
305      memset(&rasterizer, 0, sizeof rasterizer);
306      rasterizer.cull_face = PIPE_FACE_NONE;
307      rasterizer.half_pixel_center = 1;
308      rasterizer.bottom_edge_rule = 1;
309      rasterizer.depth_clip_near = 1;
310      rasterizer.depth_clip_far = 1;
311      handle = ctx->create_rasterizer_state(ctx, &rasterizer);
312      ctx->bind_rasterizer_state(ctx, handle);
313   }
314
315   set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
316   set_vertices();
317   set_vertex_shader();
318   set_fragment_shader();
319}
320
321
322static void options(int argc, char *argv[])
323{
324   int i;
325
326   for (i = 1; i < argc;) {
327      if (graw_parse_args(&i, argc, argv)) {
328         continue;
329      }
330      if (strcmp(argv[i], "-e") == 0) {
331         draw_elements = 1;
332         i++;
333      }
334      else {
335         i++;
336      }
337   }
338   if (draw_elements)
339      printf("Using pipe_context::draw_elements_instanced()\n");
340   else
341      printf("Using pipe_context::draw_arrays_instanced()\n");
342}
343
344
345int main( int argc, char *argv[] )
346{
347   options(argc, argv);
348
349   init();
350
351   graw_set_display_func( draw );
352   graw_main_loop();
353   return 0;
354}
355