g3dvl: Formatting and cleanups.
[mesa.git] / src / gallium / auxiliary / vl / vl_compositor.c
1 #include "vl_compositor.h"
2 #include <assert.h>
3 #include <pipe/p_context.h>
4 #include <pipe/p_inlines.h>
5 #include <tgsi/tgsi_parse.h>
6 #include <tgsi/tgsi_build.h>
7 #include <util/u_memory.h>
8 #include "vl_shader_build.h"
9
10 struct vertex2f
11 {
12 float x, y;
13 };
14
15 struct vertex4f
16 {
17 float x, y, z, w;
18 };
19
20 struct vertex_shader_consts
21 {
22 struct vertex4f dst_scale;
23 struct vertex4f dst_trans;
24 struct vertex4f src_scale;
25 struct vertex4f src_trans;
26 };
27
28 struct fragment_shader_consts
29 {
30 struct vertex4f bias;
31 float matrix[16];
32 };
33
34 /*
35 * Represents 2 triangles in a strip in normalized coords.
36 * Used to render the surface onto the frame buffer.
37 */
38 static const struct vertex2f surface_verts[4] =
39 {
40 {0.0f, 0.0f},
41 {0.0f, 1.0f},
42 {1.0f, 0.0f},
43 {1.0f, 1.0f}
44 };
45
46 /*
47 * Represents texcoords for the above. We can use the position values directly.
48 * TODO: Duplicate these in the shader, no need to create a buffer.
49 */
50 static const struct vertex2f *surface_texcoords = surface_verts;
51
52 /*
53 * Identity color conversion constants, for debugging
54 */
55 static const struct fragment_shader_consts identity =
56 {
57 {
58 0.0f, 0.0f, 0.0f, 0.0f
59 },
60 {
61 1.0f, 0.0f, 0.0f, 0.0f,
62 0.0f, 1.0f, 0.0f, 0.0f,
63 0.0f, 0.0f, 1.0f, 0.0f,
64 0.0f, 0.0f, 0.0f, 1.0f
65 }
66 };
67
68 /*
69 * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
70 * Y is in [16,235], Cb and Cr are in [16,240]
71 * R, G, and B are in [16,235]
72 */
73 static const struct fragment_shader_consts bt_601 =
74 {
75 {
76 0.0f, 0.501960784f, 0.501960784f, 0.0f
77 },
78 {
79 1.0f, 0.0f, 1.371f, 0.0f,
80 1.0f, -0.336f, -0.698f, 0.0f,
81 1.0f, 1.732f, 0.0f, 0.0f,
82 0.0f, 0.0f, 0.0f, 1.0f
83 }
84 };
85
86 /*
87 * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
88 * Y is in [16,235], Cb and Cr are in [16,240]
89 * R, G, and B are in [0,255]
90 */
91 static const struct fragment_shader_consts bt_601_full =
92 {
93 {
94 0.062745098f, 0.501960784f, 0.501960784f, 0.0f
95 },
96 {
97 1.164f, 0.0f, 1.596f, 0.0f,
98 1.164f, -0.391f, -0.813f, 0.0f,
99 1.164f, 2.018f, 0.0f, 0.0f,
100 0.0f, 0.0f, 0.0f, 1.0f
101 }
102 };
103
104 /*
105 * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
106 * Y is in [16,235], Cb and Cr are in [16,240]
107 * R, G, and B are in [16,235]
108 */
109 static const struct fragment_shader_consts bt_709 =
110 {
111 {
112 0.0f, 0.501960784f, 0.501960784f, 0.0f
113 },
114 {
115 1.0f, 0.0f, 1.540f, 0.0f,
116 1.0f, -0.183f, -0.459f, 0.0f,
117 1.0f, 1.816f, 0.0f, 0.0f,
118 0.0f, 0.0f, 0.0f, 1.0f
119 }
120 };
121
122 /*
123 * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
124 * Y is in [16,235], Cb and Cr are in [16,240]
125 * R, G, and B are in [0,255]
126 */
127 const struct fragment_shader_consts bt_709_full =
128 {
129 {
130 0.062745098f, 0.501960784f, 0.501960784f, 0.0f
131 },
132 {
133 1.164f, 0.0f, 1.793f, 0.0f,
134 1.164f, -0.213f, -0.534f, 0.0f,
135 1.164f, 2.115f, 0.0f, 0.0f,
136 0.0f, 0.0f, 0.0f, 1.0f
137 }
138 };
139
140 static void
141 create_vert_shader(struct vl_compositor *c)
142 {
143 const unsigned max_tokens = 50;
144
145 struct pipe_shader_state vs;
146 struct tgsi_token *tokens;
147 struct tgsi_header *header;
148
149 struct tgsi_full_declaration decl;
150 struct tgsi_full_instruction inst;
151
152 unsigned ti;
153
154 assert(c);
155
156 tokens = (struct tgsi_token*)MALLOC(max_tokens * sizeof(struct tgsi_token));
157 *(struct tgsi_version*)&tokens[0] = tgsi_build_version();
158 header = (struct tgsi_header*)&tokens[1];
159 *header = tgsi_build_header();
160 *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header);
161
162 ti = 3;
163
164 /*
165 * decl i0 ; Vertex pos
166 * decl i1 ; Vertex texcoords
167 */
168 for (unsigned i = 0; i < 2; i++) {
169 decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i);
170 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
171 }
172
173 /*
174 * decl c0 ; Scaling vector to scale vertex pos rect to destination size
175 * decl c1 ; Translation vector to move vertex pos rect into position
176 * decl c2 ; Scaling vector to scale texcoord rect to source size
177 * decl c3 ; Translation vector to move texcoord rect into position
178 */
179 decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 3);
180 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
181
182 /*
183 * decl o0 ; Vertex pos
184 * decl o1 ; Vertex texcoords
185 */
186 for (unsigned i = 0; i < 2; i++) {
187 decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i);
188 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
189 }
190
191 /* decl t0, t1 */
192 decl = vl_decl_temps(0, 1);
193 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
194
195 /*
196 * mad o0, i0, c0, c1 ; Scale and translate unit output rect to destination size and pos
197 * mad o1, i1, c2, c3 ; Scale and translate unit texcoord rect to source size and pos
198 */
199 for (unsigned i = 0; i < 2; ++i) {
200 inst = vl_inst4(TGSI_OPCODE_MAD, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i, TGSI_FILE_CONSTANT, i * 2, TGSI_FILE_CONSTANT, i * 2 + 1);
201 ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
202 }
203
204 /* end */
205 inst = vl_end();
206 ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
207
208 assert(ti <= max_tokens);
209
210 vs.tokens = tokens;
211 c->vertex_shader = c->pipe->create_vs_state(c->pipe, &vs);
212 FREE(tokens);
213 }
214
215 static void
216 create_frag_shader(struct vl_compositor *c)
217 {
218 const unsigned max_tokens = 50;
219
220 struct pipe_shader_state fs;
221 struct tgsi_token *tokens;
222 struct tgsi_header *header;
223
224 struct tgsi_full_declaration decl;
225 struct tgsi_full_instruction inst;
226
227 unsigned ti;
228
229 assert(c);
230
231 tokens = (struct tgsi_token*)MALLOC(max_tokens * sizeof(struct tgsi_token));
232 *(struct tgsi_version*)&tokens[0] = tgsi_build_version();
233 header = (struct tgsi_header*)&tokens[1];
234 *header = tgsi_build_header();
235 *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header);
236
237 ti = 3;
238
239 /* decl i0 ; Texcoords for s0 */
240 decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, 1, 0, 0, TGSI_INTERPOLATE_LINEAR);
241 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
242
243 /*
244 * decl c0 ; Bias vector for CSC
245 * decl c1-c4 ; CSC matrix c1-c4
246 */
247 decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 4);
248 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
249
250 /* decl o0 ; Fragment color */
251 decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0);
252 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
253
254 /* decl t0 */
255 decl = vl_decl_temps(0, 0);
256 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
257
258 /* decl s0 ; Sampler for tex containing picture to display */
259 decl = vl_decl_samplers(0, 0);
260 ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
261
262 /* tex2d t0, i0, s0 ; Read src pixel */
263 inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_INPUT, 0, TGSI_FILE_SAMPLER, 0);
264 ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
265
266 /* sub t0, t0, c0 ; Subtract bias vector from pixel */
267 inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0);
268 ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
269
270 /*
271 * dp4 o0.x, t0, c1 ; Multiply pixel by the color conversion matrix
272 * dp4 o0.y, t0, c2
273 * dp4 o0.z, t0, c3
274 */
275 for (unsigned i = 0; i < 3; ++i) {
276 inst = vl_inst3(TGSI_OPCODE_DP4, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, i + 1);
277 inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i;
278 ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
279 }
280
281 /* end */
282 inst = vl_end();
283 ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
284
285 assert(ti <= max_tokens);
286
287 fs.tokens = tokens;
288 c->fragment_shader = c->pipe->create_fs_state(c->pipe, &fs);
289 FREE(tokens);
290 }
291
292 static bool
293 init_pipe_state(struct vl_compositor *c)
294 {
295 struct pipe_sampler_state sampler;
296
297 assert(c);
298
299 c->fb_state.nr_cbufs = 1;
300 c->fb_state.zsbuf = NULL;
301
302 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
303 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
304 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
305 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
306 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
307 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
308 sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
309 sampler.compare_func = PIPE_FUNC_ALWAYS;
310 sampler.normalized_coords = 1;
311 /*sampler.prefilter = ;*/
312 /*sampler.lod_bias = ;*/
313 /*sampler.min_lod = ;*/
314 /*sampler.max_lod = ;*/
315 /*sampler.border_color[i] = ;*/
316 /*sampler.max_anisotropy = ;*/
317 c->sampler = c->pipe->create_sampler_state(c->pipe, &sampler);
318
319 return true;
320 }
321
322 static void cleanup_pipe_state(struct vl_compositor *c)
323 {
324 assert(c);
325
326 c->pipe->delete_sampler_state(c->pipe, c->sampler);
327 }
328
329 static bool
330 init_shaders(struct vl_compositor *c)
331 {
332 assert(c);
333
334 create_vert_shader(c);
335 create_frag_shader(c);
336
337 return true;
338 }
339
340 static void cleanup_shaders(struct vl_compositor *c)
341 {
342 assert(c);
343
344 c->pipe->delete_vs_state(c->pipe, c->vertex_shader);
345 c->pipe->delete_fs_state(c->pipe, c->fragment_shader);
346 }
347
348 static bool
349 init_buffers(struct vl_compositor *c)
350 {
351 assert(c);
352
353 /*
354 * Create our vertex buffer and vertex buffer element
355 * VB contains 4 vertices that render a quad covering the entire window
356 * to display a rendered surface
357 * Quad is rendered as a tri strip
358 */
359 c->vertex_bufs[0].stride = sizeof(struct vertex2f);
360 c->vertex_bufs[0].max_index = 3;
361 c->vertex_bufs[0].buffer_offset = 0;
362 c->vertex_bufs[0].buffer = pipe_buffer_create
363 (
364 c->pipe->screen,
365 1,
366 PIPE_BUFFER_USAGE_VERTEX,
367 sizeof(struct vertex2f) * 4
368 );
369
370 memcpy
371 (
372 pipe_buffer_map(c->pipe->screen, c->vertex_bufs[0].buffer, PIPE_BUFFER_USAGE_CPU_WRITE),
373 surface_verts,
374 sizeof(struct vertex2f) * 4
375 );
376
377 pipe_buffer_unmap(c->pipe->screen, c->vertex_bufs[0].buffer);
378
379 c->vertex_elems[0].src_offset = 0;
380 c->vertex_elems[0].vertex_buffer_index = 0;
381 c->vertex_elems[0].nr_components = 2;
382 c->vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
383
384 /*
385 * Create our texcoord buffer and texcoord buffer element
386 * Texcoord buffer contains the TCs for mapping the rendered surface to the 4 vertices
387 */
388 c->vertex_bufs[1].stride = sizeof(struct vertex2f);
389 c->vertex_bufs[1].max_index = 3;
390 c->vertex_bufs[1].buffer_offset = 0;
391 c->vertex_bufs[1].buffer = pipe_buffer_create
392 (
393 c->pipe->screen,
394 1,
395 PIPE_BUFFER_USAGE_VERTEX,
396 sizeof(struct vertex2f) * 4
397 );
398
399 memcpy
400 (
401 pipe_buffer_map(c->pipe->screen, c->vertex_bufs[1].buffer, PIPE_BUFFER_USAGE_CPU_WRITE),
402 surface_texcoords,
403 sizeof(struct vertex2f) * 4
404 );
405
406 pipe_buffer_unmap(c->pipe->screen, c->vertex_bufs[1].buffer);
407
408 c->vertex_elems[1].src_offset = 0;
409 c->vertex_elems[1].vertex_buffer_index = 1;
410 c->vertex_elems[1].nr_components = 2;
411 c->vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
412
413 /*
414 * Create our vertex shader's constant buffer
415 * Const buffer contains scaling and translation vectors
416 */
417 c->vs_const_buf.buffer = pipe_buffer_create
418 (
419 c->pipe->screen,
420 1,
421 PIPE_BUFFER_USAGE_CONSTANT | PIPE_BUFFER_USAGE_DISCARD,
422 sizeof(struct vertex_shader_consts)
423 );
424
425 /*
426 * Create our fragment shader's constant buffer
427 * Const buffer contains the color conversion matrix and bias vectors
428 */
429 c->fs_const_buf.buffer = pipe_buffer_create
430 (
431 c->pipe->screen,
432 1,
433 PIPE_BUFFER_USAGE_CONSTANT,
434 sizeof(struct fragment_shader_consts)
435 );
436
437 /*
438 * TODO: Refactor this into a seperate function,
439 * allow changing the CSC matrix at runtime to switch between regular & full versions
440 */
441 memcpy
442 (
443 pipe_buffer_map(c->pipe->screen, c->fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE),
444 &bt_601_full,
445 sizeof(struct fragment_shader_consts)
446 );
447
448 pipe_buffer_unmap(c->pipe->screen, c->fs_const_buf.buffer);
449
450 return true;
451 }
452
453 static void
454 cleanup_buffers(struct vl_compositor *c)
455 {
456 assert(c);
457
458 for (unsigned i = 0; i < 2; ++i)
459 pipe_buffer_reference(&c->vertex_bufs[i].buffer, NULL);
460
461 pipe_buffer_reference(&c->vs_const_buf.buffer, NULL);
462 pipe_buffer_reference(&c->fs_const_buf.buffer, NULL);
463 }
464
465 bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe)
466 {
467 assert(compositor);
468
469 memset(compositor, 0, sizeof(struct vl_compositor));
470
471 compositor->pipe = pipe;
472
473 if (!init_pipe_state(compositor))
474 return false;
475 if (!init_shaders(compositor)) {
476 cleanup_pipe_state(compositor);
477 return false;
478 }
479 if (!init_buffers(compositor)) {
480 cleanup_shaders(compositor);
481 cleanup_pipe_state(compositor);
482 return false;
483 }
484
485 return true;
486 }
487
488 void vl_compositor_cleanup(struct vl_compositor *compositor)
489 {
490 assert(compositor);
491
492 cleanup_buffers(compositor);
493 cleanup_shaders(compositor);
494 cleanup_pipe_state(compositor);
495 }
496
497 void vl_compositor_render(struct vl_compositor *compositor,
498 /*struct pipe_texture *backround,
499 struct pipe_video_rect *backround_area,*/
500 struct pipe_texture *src_surface,
501 enum pipe_mpeg12_picture_type picture_type,
502 /*unsigned num_past_surfaces,
503 struct pipe_texture *past_surfaces,
504 unsigned num_future_surfaces,
505 struct pipe_texture *future_surfaces,*/
506 struct pipe_video_rect *src_area,
507 struct pipe_texture *dst_surface,
508 struct pipe_video_rect *dst_area,
509 /*unsigned num_layers,
510 struct pipe_texture *layers,
511 struct pipe_video_rect *layer_src_areas,
512 struct pipe_video_rect *layer_dst_areas*/
513 struct pipe_fence_handle **fence)
514 {
515 struct vertex_shader_consts *vs_consts;
516
517 assert(compositor);
518 assert(src_surface);
519 assert(src_area);
520 assert(dst_surface);
521 assert(dst_area);
522 assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME);
523
524 compositor->fb_state.width = dst_surface->width[0];
525 compositor->fb_state.height = dst_surface->height[0];
526 compositor->fb_state.cbufs[0] = compositor->pipe->screen->get_tex_surface
527 (
528 compositor->pipe->screen,
529 dst_surface,
530 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE
531 );
532
533 compositor->viewport.scale[0] = compositor->fb_state.width;
534 compositor->viewport.scale[1] = compositor->fb_state.height;
535 compositor->viewport.scale[2] = 1;
536 compositor->viewport.scale[3] = 1;
537 compositor->viewport.translate[0] = 0;
538 compositor->viewport.translate[1] = 0;
539 compositor->viewport.translate[2] = 0;
540 compositor->viewport.translate[3] = 0;
541
542 compositor->pipe->set_framebuffer_state(compositor->pipe, &compositor->fb_state);
543 compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport);
544 compositor->pipe->bind_sampler_states(compositor->pipe, 1, &compositor->sampler);
545 compositor->pipe->set_sampler_textures(compositor->pipe, 1, &src_surface);
546 compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader);
547 compositor->pipe->bind_fs_state(compositor->pipe, compositor->fragment_shader);
548 compositor->pipe->set_vertex_buffers(compositor->pipe, 2, compositor->vertex_bufs);
549 compositor->pipe->set_vertex_elements(compositor->pipe, 2, compositor->vertex_elems);
550 compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_VERTEX, 0, &compositor->vs_const_buf);
551 compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, &compositor->fs_const_buf);
552
553 vs_consts = pipe_buffer_map
554 (
555 compositor->pipe->screen,
556 compositor->vs_const_buf.buffer,
557 PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD
558 );
559
560 vs_consts->dst_scale.x = dst_area->w / (float)compositor->fb_state.cbufs[0]->width;
561 vs_consts->dst_scale.y = dst_area->h / (float)compositor->fb_state.cbufs[0]->height;
562 vs_consts->dst_scale.z = 1;
563 vs_consts->dst_scale.w = 1;
564 vs_consts->dst_trans.x = dst_area->x / (float)compositor->fb_state.cbufs[0]->width;
565 vs_consts->dst_trans.y = dst_area->y / (float)compositor->fb_state.cbufs[0]->height;
566 vs_consts->dst_trans.z = 0;
567 vs_consts->dst_trans.w = 0;
568
569 vs_consts->src_scale.x = src_area->w / (float)src_surface->width[0];
570 vs_consts->src_scale.y = src_area->h / (float)src_surface->height[0];
571 vs_consts->src_scale.z = 1;
572 vs_consts->src_scale.w = 1;
573 vs_consts->src_trans.x = src_area->x / (float)src_surface->width[0];
574 vs_consts->src_trans.y = src_area->y / (float)src_surface->height[0];
575 vs_consts->src_trans.z = 0;
576 vs_consts->src_trans.w = 0;
577
578 pipe_buffer_unmap(compositor->pipe->screen, compositor->vs_const_buf.buffer);
579
580 compositor->pipe->draw_arrays(compositor->pipe, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
581 compositor->pipe->flush(compositor->pipe, PIPE_FLUSH_RENDER_CACHE, fence);
582
583 pipe_surface_reference(&compositor->fb_state.cbufs[0], NULL);
584 }