2 #include "vl_basic_csc.h"
4 #include <pipe/p_context.h>
5 #include <pipe/p_state.h>
6 #include <pipe/p_inlines.h>
7 #include <tgsi/tgsi_parse.h>
8 #include <tgsi/tgsi_build.h>
9 #include <util/u_memory.h>
11 #include "vl_surface.h"
12 #include "vl_shader_build.h"
15 struct vlVertexShaderConsts
17 struct vlVertex4f dst_scale
;
18 struct vlVertex4f dst_trans
;
19 struct vlVertex4f src_scale
;
20 struct vlVertex4f src_trans
;
23 struct vlFragmentShaderConsts
25 struct vlVertex4f bias
;
33 struct pipe_context
*pipe
;
34 struct pipe_viewport_state viewport
;
35 struct pipe_framebuffer_state framebuffer
;
36 struct pipe_texture
*framebuffer_tex
;
38 void *vertex_shader
, *fragment_shader
;
39 struct pipe_vertex_buffer vertex_bufs
[2];
40 struct pipe_vertex_element vertex_elems
[2];
41 struct pipe_constant_buffer vs_const_buf
, fs_const_buf
;
44 static int vlResizeFrameBuffer
51 struct vlBasicCSC
*basic_csc
;
52 struct pipe_context
*pipe
;
53 struct pipe_texture
template;
57 basic_csc
= (struct vlBasicCSC
*)csc
;
58 pipe
= basic_csc
->pipe
;
60 if (basic_csc
->framebuffer
.width
== width
&& basic_csc
->framebuffer
.height
== height
)
63 basic_csc
->viewport
.scale
[0] = width
;
64 basic_csc
->viewport
.scale
[1] = height
;
65 basic_csc
->viewport
.scale
[2] = 1;
66 basic_csc
->viewport
.scale
[3] = 1;
67 basic_csc
->viewport
.translate
[0] = 0;
68 basic_csc
->viewport
.translate
[1] = 0;
69 basic_csc
->viewport
.translate
[2] = 0;
70 basic_csc
->viewport
.translate
[3] = 0;
72 if (basic_csc
->framebuffer_tex
)
74 pipe_surface_reference(&basic_csc
->framebuffer
.cbufs
[0], NULL
);
75 pipe_texture_reference(&basic_csc
->framebuffer_tex
, NULL
);
78 memset(&template, 0, sizeof(struct pipe_texture
));
79 template.target
= PIPE_TEXTURE_2D
;
80 template.format
= PIPE_FORMAT_A8R8G8B8_UNORM
;
81 template.last_level
= 0;
82 template.width
[0] = width
;
83 template.height
[0] = height
;
84 template.depth
[0] = 1;
85 template.compressed
= 0;
86 pf_get_block(template.format
, &template.block
);
87 template.tex_usage
= PIPE_TEXTURE_USAGE_DISPLAY_TARGET
;
89 basic_csc
->framebuffer_tex
= pipe
->screen
->texture_create(pipe
->screen
, &template);
91 basic_csc
->framebuffer
.width
= width
;
92 basic_csc
->framebuffer
.height
= height
;
93 basic_csc
->framebuffer
.cbufs
[0] = pipe
->screen
->get_tex_surface
96 basic_csc
->framebuffer_tex
,
97 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ
| PIPE_BUFFER_USAGE_GPU_WRITE
100 /* Clear to black, in case video doesn't fill the entire window */
101 pipe
->clear(pipe
, basic_csc
->framebuffer
.cbufs
[0], 0);
111 struct vlBasicCSC
*basic_csc
;
112 struct pipe_context
*pipe
;
116 basic_csc
= (struct vlBasicCSC
*)csc
;
117 pipe
= basic_csc
->pipe
;
119 pipe
->set_framebuffer_state(pipe
, &basic_csc
->framebuffer
);
120 pipe
->set_viewport_state(pipe
, &basic_csc
->viewport
);
121 pipe
->bind_sampler_states(pipe
, 1, (void**)&basic_csc
->sampler
);
122 /* Source texture set in vlPutPictureCSC() */
123 pipe
->bind_vs_state(pipe
, basic_csc
->vertex_shader
);
124 pipe
->bind_fs_state(pipe
, basic_csc
->fragment_shader
);
125 pipe
->set_vertex_buffers(pipe
, 2, basic_csc
->vertex_bufs
);
126 pipe
->set_vertex_elements(pipe
, 2, basic_csc
->vertex_elems
);
127 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_VERTEX
, 0, &basic_csc
->vs_const_buf
);
128 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_FRAGMENT
, 0, &basic_csc
->fs_const_buf
);
133 static int vlPutPictureCSC
136 struct vlSurface
*surface
,
145 enum vlPictureType picture_type
148 struct vlBasicCSC
*basic_csc
;
149 struct pipe_context
*pipe
;
150 struct vlVertexShaderConsts
*vs_consts
;
155 basic_csc
= (struct vlBasicCSC
*)csc
;
156 pipe
= basic_csc
->pipe
;
158 vs_consts
= pipe_buffer_map
161 basic_csc
->vs_const_buf
.buffer
,
162 PIPE_BUFFER_USAGE_CPU_WRITE
| PIPE_BUFFER_USAGE_DISCARD
165 vs_consts
->dst_scale
.x
= destw
/ (float)basic_csc
->framebuffer
.cbufs
[0]->width
;
166 vs_consts
->dst_scale
.y
= desth
/ (float)basic_csc
->framebuffer
.cbufs
[0]->height
;
167 vs_consts
->dst_scale
.z
= 1;
168 vs_consts
->dst_scale
.w
= 1;
169 vs_consts
->dst_trans
.x
= destx
/ (float)basic_csc
->framebuffer
.cbufs
[0]->width
;
170 vs_consts
->dst_trans
.y
= desty
/ (float)basic_csc
->framebuffer
.cbufs
[0]->height
;
171 vs_consts
->dst_trans
.z
= 0;
172 vs_consts
->dst_trans
.w
= 0;
174 vs_consts
->src_scale
.x
= srcw
/ (float)surface
->texture
->width
[0];
175 vs_consts
->src_scale
.y
= srch
/ (float)surface
->texture
->height
[0];
176 vs_consts
->src_scale
.z
= 1;
177 vs_consts
->src_scale
.w
= 1;
178 vs_consts
->src_trans
.x
= srcx
/ (float)surface
->texture
->width
[0];
179 vs_consts
->src_trans
.y
= srcy
/ (float)surface
->texture
->height
[0];
180 vs_consts
->src_trans
.z
= 0;
181 vs_consts
->src_trans
.w
= 0;
183 pipe_buffer_unmap(pipe
->screen
, basic_csc
->vs_const_buf
.buffer
);
185 pipe
->set_sampler_textures(pipe
, 1, &surface
->texture
);
186 pipe
->draw_arrays(pipe
, PIPE_PRIM_TRIANGLE_STRIP
, 0, 4);
201 static struct pipe_surface
* vlGetFrameBuffer
206 struct vlBasicCSC
*basic_csc
;
210 basic_csc
= (struct vlBasicCSC
*)csc
;
212 return basic_csc
->framebuffer
.cbufs
[0];
220 struct vlBasicCSC
*basic_csc
;
221 struct pipe_context
*pipe
;
226 basic_csc
= (struct vlBasicCSC
*)csc
;
227 pipe
= basic_csc
->pipe
;
229 if (basic_csc
->framebuffer_tex
)
231 pipe_surface_reference(&basic_csc
->framebuffer
.cbufs
[0], NULL
);
232 pipe_texture_reference(&basic_csc
->framebuffer_tex
, NULL
);
235 pipe
->delete_sampler_state(pipe
, basic_csc
->sampler
);
236 pipe
->delete_vs_state(pipe
, basic_csc
->vertex_shader
);
237 pipe
->delete_fs_state(pipe
, basic_csc
->fragment_shader
);
239 for (i
= 0; i
< 2; ++i
)
240 pipe_buffer_reference(pipe
->screen
, &basic_csc
->vertex_bufs
[i
].buffer
, NULL
);
242 pipe_buffer_reference(pipe
->screen
, &basic_csc
->vs_const_buf
.buffer
, NULL
);
243 pipe_buffer_reference(pipe
->screen
, &basic_csc
->fs_const_buf
.buffer
, NULL
);
251 * Represents 2 triangles in a strip in normalized coords.
252 * Used to render the surface onto the frame buffer.
254 static const struct vlVertex2f surface_verts
[4] =
263 * Represents texcoords for the above. We can use the position values directly.
264 * TODO: Duplicate these in the shader, no need to create a buffer.
266 static const struct vlVertex2f
*surface_texcoords
= surface_verts
;
269 * Identity color conversion constants, for debugging
271 static const struct vlFragmentShaderConsts identity
=
274 0.0f
, 0.0f
, 0.0f
, 0.0f
277 1.0f
, 0.0f
, 0.0f
, 0.0f
,
278 0.0f
, 1.0f
, 0.0f
, 0.0f
,
279 0.0f
, 0.0f
, 1.0f
, 0.0f
,
280 0.0f
, 0.0f
, 0.0f
, 1.0f
285 * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
286 * Y is in [16,235], Cb and Cr are in [16,240]
287 * R, G, and B are in [16,235]
289 static const struct vlFragmentShaderConsts bt_601
=
292 0.0f
, 0.501960784f
, 0.501960784f
, 0.0f
295 1.0f
, 0.0f
, 1.371f
, 0.0f
,
296 1.0f
, -0.336f
, -0.698f
, 0.0f
,
297 1.0f
, 1.732f
, 0.0f
, 0.0f
,
298 0.0f
, 0.0f
, 0.0f
, 1.0f
303 * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
304 * Y is in [16,235], Cb and Cr are in [16,240]
305 * R, G, and B are in [0,255]
307 static const struct vlFragmentShaderConsts bt_601_full
=
310 0.062745098f
, 0.501960784f
, 0.501960784f
, 0.0f
313 1.164f
, 0.0f
, 1.596f
, 0.0f
,
314 1.164f
, -0.391f
, -0.813f
, 0.0f
,
315 1.164f
, 2.018f
, 0.0f
, 0.0f
,
316 0.0f
, 0.0f
, 0.0f
, 1.0f
321 * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
322 * Y is in [16,235], Cb and Cr are in [16,240]
323 * R, G, and B are in [16,235]
325 static const struct vlFragmentShaderConsts bt_709
=
328 0.0f
, 0.501960784f
, 0.501960784f
, 0.0f
331 1.0f
, 0.0f
, 1.540f
, 0.0f
,
332 1.0f
, -0.183f
, -0.459f
, 0.0f
,
333 1.0f
, 1.816f
, 0.0f
, 0.0f
,
334 0.0f
, 0.0f
, 0.0f
, 1.0f
339 * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
340 * Y is in [16,235], Cb and Cr are in [16,240]
341 * R, G, and B are in [0,255]
343 const struct vlFragmentShaderConsts bt_709_full
=
346 0.062745098f
, 0.501960784f
, 0.501960784f
, 0.0f
349 1.164f
, 0.0f
, 1.793f
, 0.0f
,
350 1.164f
, -0.213f
, -0.534f
, 0.0f
,
351 1.164f
, 2.115f
, 0.0f
, 0.0f
,
352 0.0f
, 0.0f
, 0.0f
, 1.0f
356 static int vlCreateVertexShader
358 struct vlBasicCSC
*csc
361 const unsigned int max_tokens
= 50;
363 struct pipe_context
*pipe
;
364 struct pipe_shader_state vs
;
365 struct tgsi_token
*tokens
;
366 struct tgsi_header
*header
;
368 struct tgsi_full_declaration decl
;
369 struct tgsi_full_instruction inst
;
377 tokens
= (struct tgsi_token
*)MALLOC(max_tokens
* sizeof(struct tgsi_token
));
380 *(struct tgsi_version
*)&tokens
[0] = tgsi_build_version();
382 header
= (struct tgsi_header
*)&tokens
[1];
383 *header
= tgsi_build_header();
385 *(struct tgsi_processor
*)&tokens
[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX
, header
);
390 * decl i0 ; Vertex pos
391 * decl i1 ; Vertex texcoords
393 for (i
= 0; i
< 2; i
++)
395 decl
= vl_decl_input(i
== 0 ? TGSI_SEMANTIC_POSITION
: TGSI_SEMANTIC_GENERIC
, i
, i
, i
);
396 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
400 * decl c0 ; Scaling vector to scale vertex pos rect to destination size
401 * decl c1 ; Translation vector to move vertex pos rect into position
402 * decl c2 ; Scaling vector to scale texcoord rect to source size
403 * decl c3 ; Translation vector to move texcoord rect into position
405 decl
= vl_decl_constants(TGSI_SEMANTIC_GENERIC
, 0, 0, 3);
406 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
409 * decl o0 ; Vertex pos
410 * decl o1 ; Vertex texcoords
412 for (i
= 0; i
< 2; i
++)
414 decl
= vl_decl_output(i
== 0 ? TGSI_SEMANTIC_POSITION
: TGSI_SEMANTIC_GENERIC
, i
, i
, i
);
415 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
419 decl
= vl_decl_temps(0, 1);
420 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
423 * madd o0, i0, c0, c1 ; Scale and translate unit output rect to destination size and pos
424 * madd o1, i1, c2, c3 ; Scale and translate unit texcoord rect to source size and pos
426 for (i
= 0; i
< 2; ++i
)
428 inst
= vl_inst4(TGSI_OPCODE_MADD
, TGSI_FILE_OUTPUT
, i
, TGSI_FILE_INPUT
, i
, TGSI_FILE_CONSTANT
, i
* 2, TGSI_FILE_CONSTANT
, i
* 2 + 1);
429 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
434 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
437 csc
->vertex_shader
= pipe
->create_vs_state(pipe
, &vs
);
443 static int vlCreateFragmentShader
445 struct vlBasicCSC
*csc
448 const unsigned int max_tokens
= 50;
450 struct pipe_context
*pipe
;
451 struct pipe_shader_state fs
;
452 struct tgsi_token
*tokens
;
453 struct tgsi_header
*header
;
455 struct tgsi_full_declaration decl
;
456 struct tgsi_full_instruction inst
;
464 tokens
= (struct tgsi_token
*)MALLOC(max_tokens
* sizeof(struct tgsi_token
));
467 *(struct tgsi_version
*)&tokens
[0] = tgsi_build_version();
469 header
= (struct tgsi_header
*)&tokens
[1];
470 *header
= tgsi_build_header();
472 *(struct tgsi_processor
*)&tokens
[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT
, header
);
476 /* decl i0 ; Texcoords for s0 */
477 decl
= vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC
, 1, 0, 0, TGSI_INTERPOLATE_LINEAR
);
478 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
481 * decl c0 ; Bias vector for CSC
482 * decl c1-c4 ; CSC matrix c1-c4
484 decl
= vl_decl_constants(TGSI_SEMANTIC_GENERIC
, 0, 0, 4);
485 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
487 /* decl o0 ; Fragment color */
488 decl
= vl_decl_output(TGSI_SEMANTIC_COLOR
, 0, 0, 0);
489 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
492 decl
= vl_decl_temps(0, 0);
493 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
495 /* decl s0 ; Sampler for tex containing picture to display */
496 decl
= vl_decl_samplers(0, 0);
497 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
499 /* tex2d t0, i0, s0 ; Read src pixel */
500 inst
= vl_tex(TGSI_TEXTURE_2D
, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_INPUT
, 0, TGSI_FILE_SAMPLER
, 0);
501 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
503 /* sub t0, t0, c0 ; Subtract bias vector from pixel */
504 inst
= vl_inst3(TGSI_OPCODE_SUB
, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_CONSTANT
, 0);
505 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
508 * dp4 o0.x, t0, c1 ; Multiply pixel by the color conversion matrix
512 for (i
= 0; i
< 3; ++i
)
514 inst
= vl_inst3(TGSI_OPCODE_DP4
, TGSI_FILE_OUTPUT
, 0, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_CONSTANT
, i
+ 1);
515 inst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_X
<< i
;
516 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
521 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
524 csc
->fragment_shader
= pipe
->create_fs_state(pipe
, &fs
);
530 static int vlCreateDataBufs
532 struct vlBasicCSC
*csc
535 struct pipe_context
*pipe
;
542 * Create our vertex buffer and vertex buffer element
543 * VB contains 4 vertices that render a quad covering the entire window
544 * to display a rendered surface
545 * Quad is rendered as a tri strip
547 csc
->vertex_bufs
[0].stride
= sizeof(struct vlVertex2f
);
548 csc
->vertex_bufs
[0].max_index
= 3;
549 csc
->vertex_bufs
[0].buffer_offset
= 0;
550 csc
->vertex_bufs
[0].buffer
= pipe_buffer_create
554 PIPE_BUFFER_USAGE_VERTEX
,
555 sizeof(struct vlVertex2f
) * 4
560 pipe_buffer_map(pipe
->screen
, csc
->vertex_bufs
[0].buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
),
562 sizeof(struct vlVertex2f
) * 4
565 pipe_buffer_unmap(pipe
->screen
, csc
->vertex_bufs
[0].buffer
);
567 csc
->vertex_elems
[0].src_offset
= 0;
568 csc
->vertex_elems
[0].vertex_buffer_index
= 0;
569 csc
->vertex_elems
[0].nr_components
= 2;
570 csc
->vertex_elems
[0].src_format
= PIPE_FORMAT_R32G32_FLOAT
;
573 * Create our texcoord buffer and texcoord buffer element
574 * Texcoord buffer contains the TCs for mapping the rendered surface to the 4 vertices
576 csc
->vertex_bufs
[1].stride
= sizeof(struct vlVertex2f
);
577 csc
->vertex_bufs
[1].max_index
= 3;
578 csc
->vertex_bufs
[1].buffer_offset
= 0;
579 csc
->vertex_bufs
[1].buffer
= pipe_buffer_create
583 PIPE_BUFFER_USAGE_VERTEX
,
584 sizeof(struct vlVertex2f
) * 4
589 pipe_buffer_map(pipe
->screen
, csc
->vertex_bufs
[1].buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
),
591 sizeof(struct vlVertex2f
) * 4
594 pipe_buffer_unmap(pipe
->screen
, csc
->vertex_bufs
[1].buffer
);
596 csc
->vertex_elems
[1].src_offset
= 0;
597 csc
->vertex_elems
[1].vertex_buffer_index
= 1;
598 csc
->vertex_elems
[1].nr_components
= 2;
599 csc
->vertex_elems
[1].src_format
= PIPE_FORMAT_R32G32_FLOAT
;
602 * Create our vertex shader's constant buffer
603 * Const buffer contains scaling and translation vectors
605 csc
->vs_const_buf
.buffer
= pipe_buffer_create
609 PIPE_BUFFER_USAGE_CONSTANT
| PIPE_BUFFER_USAGE_DISCARD
,
610 sizeof(struct vlVertexShaderConsts
)
614 * Create our fragment shader's constant buffer
615 * Const buffer contains the color conversion matrix and bias vectors
617 csc
->fs_const_buf
.buffer
= pipe_buffer_create
621 PIPE_BUFFER_USAGE_CONSTANT
,
622 sizeof(struct vlFragmentShaderConsts
)
626 * TODO: Refactor this into a seperate function,
627 * allow changing the CSC matrix at runtime to switch between regular & full versions
631 pipe_buffer_map(pipe
->screen
, csc
->fs_const_buf
.buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
),
633 sizeof(struct vlFragmentShaderConsts
)
636 pipe_buffer_unmap(pipe
->screen
, csc
->fs_const_buf
.buffer
);
643 struct vlBasicCSC
*csc
646 struct pipe_context
*pipe
;
647 struct pipe_sampler_state sampler
;
653 /* Delay creating the FB until vlPutPictureCSC() so we know window size */
654 csc
->framebuffer_tex
= NULL
;
655 csc
->framebuffer
.width
= 0;
656 csc
->framebuffer
.height
= 0;
657 csc
->framebuffer
.nr_cbufs
= 1;
658 csc
->framebuffer
.cbufs
[0] = NULL
;
659 csc
->framebuffer
.zsbuf
= NULL
;
661 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
662 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
663 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
664 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
665 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
666 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
667 sampler
.compare_mode
= PIPE_TEX_COMPARE_NONE
;
668 sampler
.compare_func
= PIPE_FUNC_ALWAYS
;
669 sampler
.normalized_coords
= 1;
670 /*sampler.prefilter = ;*/
671 /*sampler.shadow_ambient = ;*/
672 /*sampler.lod_bias = ;*/
673 /*sampler.min_lod = ;*/
674 /*sampler.max_lod = ;*/
675 /*sampler.border_color[i] = ;*/
676 /*sampler.max_anisotropy = ;*/
677 csc
->sampler
= pipe
->create_sampler_state(pipe
, &sampler
);
679 vlCreateVertexShader(csc
);
680 vlCreateFragmentShader(csc
);
681 vlCreateDataBufs(csc
);
688 struct pipe_context
*pipe
,
692 struct vlBasicCSC
*basic_csc
;
697 basic_csc
= CALLOC_STRUCT(vlBasicCSC
);
702 basic_csc
->base
.vlResizeFrameBuffer
= &vlResizeFrameBuffer
;
703 basic_csc
->base
.vlBegin
= &vlBegin
;
704 basic_csc
->base
.vlPutPicture
= &vlPutPictureCSC
;
705 basic_csc
->base
.vlEnd
= &vlEnd
;
706 basic_csc
->base
.vlGetFrameBuffer
= &vlGetFrameBuffer
;
707 basic_csc
->base
.vlDestroy
= &vlDestroy
;
708 basic_csc
->pipe
= pipe
;
712 *csc
= &basic_csc
->base
;