1/* 2 * Test draw instancing. 3 */ 4 5#include <stdio.h> 6#include <string.h> 7 8#include "frontend/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 vp.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X; 100 vp.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y; 101 vp.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z; 102 vp.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W; 103 104 ctx->set_viewport_states( ctx, 0, 1, &vp ); 105} 106 107 108static void set_vertices( void ) 109{ 110 struct pipe_vertex_element ve[3]; 111 struct pipe_vertex_buffer vbuf[2]; 112 void *handle; 113 114 memset(ve, 0, sizeof ve); 115 116 /* pos */ 117 ve[0].src_offset = Offset(struct vertex, position); 118 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 119 ve[0].vertex_buffer_index = 0; 120 121 /* color */ 122 ve[1].src_offset = Offset(struct vertex, color); 123 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 124 ve[1].vertex_buffer_index = 0; 125 126 /* per-instance info */ 127 ve[2].src_offset = 0; 128 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 129 ve[2].vertex_buffer_index = 1; 130 ve[2].instance_divisor = 1; 131 132 handle = ctx->create_vertex_elements_state(ctx, 3, ve); 133 ctx->bind_vertex_elements_state(ctx, handle); 134 135 memset(&vbuf, 0, sizeof vbuf); 136 137 /* vertex data */ 138 vbuf[0].stride = sizeof( struct vertex ); 139 vbuf[0].buffer_offset = 0; 140 vbuf[0].buffer.resource = pipe_buffer_create_with_data(ctx, 141 PIPE_BIND_VERTEX_BUFFER, 142 PIPE_USAGE_DEFAULT, 143 sizeof(vertices), 144 vertices); 145 146 /* instance data */ 147 vbuf[1].stride = sizeof( inst_data[0] ); 148 vbuf[1].buffer_offset = 0; 149 vbuf[1].buffer.resource = pipe_buffer_create_with_data(ctx, 150 PIPE_BIND_VERTEX_BUFFER, 151 PIPE_USAGE_DEFAULT, 152 sizeof(inst_data), 153 inst_data); 154 155 ctx->set_vertex_buffers(ctx, 0, 2, 0, false, vbuf); 156} 157 158static void set_vertex_shader( void ) 159{ 160 void *handle; 161 const char *text = 162 "VERT\n" 163 "DCL IN[0]\n" 164 "DCL IN[1]\n" 165 "DCL IN[2]\n" 166 "DCL OUT[0], POSITION\n" 167 "DCL OUT[1], COLOR\n" 168 " 0: MOV OUT[1], IN[1]\n" 169 " 1: ADD OUT[0], IN[0], IN[2]\n" /* add instance pos to vertex pos */ 170 " 2: END\n"; 171 172 handle = graw_parse_vertex_shader(ctx, text); 173 ctx->bind_vs_state(ctx, handle); 174} 175 176static void set_fragment_shader( void ) 177{ 178 void *handle; 179 const char *text = 180 "FRAG\n" 181 "DCL IN[0], COLOR, LINEAR\n" 182 "DCL OUT[0], COLOR\n" 183 " 0: MOV OUT[0], IN[0]\n" 184 " 1: END\n"; 185 186 handle = graw_parse_fragment_shader(ctx, text); 187 ctx->bind_fs_state(ctx, handle); 188} 189 190 191static void draw( void ) 192{ 193 union pipe_color_union clear_color = { {1,0,1,1} }; 194 struct pipe_draw_info info; 195 struct pipe_draw_start_count_bias draw; 196 197 ctx->clear(ctx, PIPE_CLEAR_COLOR, NULL, &clear_color, 0, 0); 198 199 200 util_draw_init_info(&info); 201 info.index_size = draw_elements ? 2 : 0; 202 info.mode = PIPE_PRIM_TRIANGLES; 203 draw.start = 0; 204 draw.count = 3; 205 draw.index_bias = 0; 206 /* draw NUM_INST triangles */ 207 info.instance_count = NUM_INST; 208 209 /* index data */ 210 if (info.index_size) { 211 info.index.resource = 212 pipe_buffer_create_with_data(ctx, 213 PIPE_BIND_INDEX_BUFFER, 214 PIPE_USAGE_DEFAULT, 215 sizeof(indices), 216 indices); 217 } 218 219 ctx->draw_vbo(ctx, &info, 0, NULL, &draw, 1); 220 221 pipe_resource_reference(&info.index.resource, NULL); 222 223 ctx->flush(ctx, NULL, 0); 224 225 graw_save_surface_to_file(ctx, surf, NULL); 226 227 screen->flush_frontbuffer(screen, ctx, tex, 0, 0, window, NULL); 228} 229 230 231static void init( void ) 232{ 233 struct pipe_framebuffer_state fb; 234 struct pipe_resource templat; 235 struct pipe_surface surf_tmpl; 236 int i; 237 238 /* It's hard to say whether window or screen should be created 239 * first. Different environments would prefer one or the other. 240 * 241 * Also, no easy way of querying supported formats if the screen 242 * cannot be created first. 243 */ 244 for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) { 245 screen = graw_create_window_and_screen(0, 0, 300, 300, 246 formats[i], 247 &window); 248 if (window && screen) 249 break; 250 } 251 if (!screen || !window) { 252 fprintf(stderr, "Unable to create window\n"); 253 exit(1); 254 } 255 256 ctx = screen->context_create(screen, NULL, 0); 257 if (ctx == NULL) 258 exit(3); 259 260 memset(&templat, 0, sizeof(templat)); 261 templat.target = PIPE_TEXTURE_2D; 262 templat.format = formats[i]; 263 templat.width0 = WIDTH; 264 templat.height0 = HEIGHT; 265 templat.depth0 = 1; 266 templat.array_size = 1; 267 templat.last_level = 0; 268 templat.bind = (PIPE_BIND_RENDER_TARGET | 269 PIPE_BIND_DISPLAY_TARGET); 270 271 tex = screen->resource_create(screen, 272 &templat); 273 if (tex == NULL) 274 exit(4); 275 276 surf_tmpl.format = templat.format; 277 surf_tmpl.u.tex.level = 0; 278 surf_tmpl.u.tex.first_layer = 0; 279 surf_tmpl.u.tex.last_layer = 0; 280 surf = ctx->create_surface(ctx, tex, &surf_tmpl); 281 if (surf == NULL) 282 exit(5); 283 284 memset(&fb, 0, sizeof fb); 285 fb.nr_cbufs = 1; 286 fb.width = WIDTH; 287 fb.height = HEIGHT; 288 fb.cbufs[0] = surf; 289 290 ctx->set_framebuffer_state(ctx, &fb); 291 292 { 293 struct pipe_blend_state blend; 294 void *handle; 295 memset(&blend, 0, sizeof blend); 296 blend.rt[0].colormask = PIPE_MASK_RGBA; 297 handle = ctx->create_blend_state(ctx, &blend); 298 ctx->bind_blend_state(ctx, handle); 299 } 300 301 { 302 struct pipe_depth_stencil_alpha_state depthstencil; 303 void *handle; 304 memset(&depthstencil, 0, sizeof depthstencil); 305 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil); 306 ctx->bind_depth_stencil_alpha_state(ctx, handle); 307 } 308 309 { 310 struct pipe_rasterizer_state rasterizer; 311 void *handle; 312 memset(&rasterizer, 0, sizeof rasterizer); 313 rasterizer.cull_face = PIPE_FACE_NONE; 314 rasterizer.half_pixel_center = 1; 315 rasterizer.bottom_edge_rule = 1; 316 rasterizer.depth_clip_near = 1; 317 rasterizer.depth_clip_far = 1; 318 handle = ctx->create_rasterizer_state(ctx, &rasterizer); 319 ctx->bind_rasterizer_state(ctx, handle); 320 } 321 322 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000); 323 set_vertices(); 324 set_vertex_shader(); 325 set_fragment_shader(); 326} 327 328 329static void options(int argc, char *argv[]) 330{ 331 int i; 332 333 for (i = 1; i < argc;) { 334 if (graw_parse_args(&i, argc, argv)) { 335 continue; 336 } 337 if (strcmp(argv[i], "-e") == 0) { 338 draw_elements = 1; 339 i++; 340 } 341 else { 342 i++; 343 } 344 } 345 if (draw_elements) 346 printf("Using pipe_context::draw_elements_instanced()\n"); 347 else 348 printf("Using pipe_context::draw_arrays_instanced()\n"); 349} 350 351 352int main( int argc, char *argv[] ) 353{ 354 options(argc, argv); 355 356 init(); 357 358 graw_set_display_func( draw ); 359 graw_main_loop(); 360 return 0; 361} 362