2 #include "vl_basic_csc.h"
5 #include <pipe/p_context.h>
6 #include <pipe/p_winsys.h>
7 #include <pipe/p_state.h>
8 #include <pipe/p_inlines.h>
9 #include <tgsi/tgsi_parse.h>
10 #include <tgsi/tgsi_build.h>
12 #include "vl_surface.h"
13 #include "vl_shader_build.h"
16 struct vlVertexShaderConsts
18 struct vlVertex4f dst_scale
;
19 struct vlVertex4f dst_trans
;
20 struct vlVertex4f src_scale
;
21 struct vlVertex4f src_trans
;
24 struct vlFragmentShaderConsts
26 struct vlVertex4f bias
;
34 struct pipe_context
*pipe
;
35 struct pipe_viewport_state viewport
;
36 struct pipe_framebuffer_state framebuffer
;
37 struct pipe_texture
*framebuffer_tex
;
39 void *vertex_shader
, *fragment_shader
;
40 struct pipe_vertex_buffer vertex_bufs
[2];
41 struct pipe_vertex_element vertex_elems
[2];
42 struct pipe_constant_buffer vs_const_buf
, fs_const_buf
;
45 static int vlResizeFrameBuffer
52 struct vlBasicCSC
*basic_csc
;
53 struct pipe_context
*pipe
;
54 struct pipe_texture
template;
58 basic_csc
= (struct vlBasicCSC
*)csc
;
59 pipe
= basic_csc
->pipe
;
61 if (basic_csc
->framebuffer
.width
== width
&& basic_csc
->framebuffer
.height
== height
)
64 basic_csc
->viewport
.scale
[0] = width
;
65 basic_csc
->viewport
.scale
[1] = height
;
66 basic_csc
->viewport
.scale
[2] = 1;
67 basic_csc
->viewport
.scale
[3] = 1;
68 basic_csc
->viewport
.translate
[0] = 0;
69 basic_csc
->viewport
.translate
[1] = 0;
70 basic_csc
->viewport
.translate
[2] = 0;
71 basic_csc
->viewport
.translate
[3] = 0;
73 if (basic_csc
->framebuffer_tex
)
74 pipe_texture_release(&basic_csc
->framebuffer_tex
);
76 memset(&template, 0, sizeof(struct pipe_texture
));
77 template.target
= PIPE_TEXTURE_2D
;
78 template.format
= PIPE_FORMAT_A8R8G8B8_UNORM
;
79 template.last_level
= 0;
80 template.width
[0] = width
;
81 template.height
[0] = height
;
82 template.depth
[0] = 1;
83 template.compressed
= 0;
84 pf_get_block(template.format
, &template.block
);
85 template.tex_usage
= PIPE_TEXTURE_USAGE_DISPLAY_TARGET
;
87 basic_csc
->framebuffer_tex
= pipe
->screen
->texture_create(pipe
->screen
, &template);
89 basic_csc
->framebuffer
.width
= width
;
90 basic_csc
->framebuffer
.height
= height
;
91 basic_csc
->framebuffer
.cbufs
[0] = pipe
->screen
->get_tex_surface
94 basic_csc
->framebuffer_tex
,
95 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ
| PIPE_BUFFER_USAGE_GPU_WRITE
98 /* Clear to black, in case video doesn't fill the entire window */
99 pipe
->clear(pipe
, basic_csc
->framebuffer
.cbufs
[0], 0);
109 struct vlBasicCSC
*basic_csc
;
110 struct pipe_context
*pipe
;
114 basic_csc
= (struct vlBasicCSC
*)csc
;
115 pipe
= basic_csc
->pipe
;
117 pipe
->set_framebuffer_state(pipe
, &basic_csc
->framebuffer
);
118 pipe
->set_viewport_state(pipe
, &basic_csc
->viewport
);
119 pipe
->bind_sampler_states(pipe
, 1, (void**)&basic_csc
->sampler
);
120 /* Source texture set in vlPutPictureCSC() */
121 pipe
->bind_vs_state(pipe
, basic_csc
->vertex_shader
);
122 pipe
->bind_fs_state(pipe
, basic_csc
->fragment_shader
);
123 pipe
->set_vertex_buffers(pipe
, 2, basic_csc
->vertex_bufs
);
124 pipe
->set_vertex_elements(pipe
, 2, basic_csc
->vertex_elems
);
125 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_VERTEX
, 0, &basic_csc
->vs_const_buf
);
126 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_FRAGMENT
, 0, &basic_csc
->fs_const_buf
);
131 static int vlPutPictureCSC
134 struct vlSurface
*surface
,
143 enum vlPictureType picture_type
146 struct vlBasicCSC
*basic_csc
;
147 struct pipe_context
*pipe
;
148 struct vlVertexShaderConsts
*vs_consts
;
153 basic_csc
= (struct vlBasicCSC
*)csc
;
154 pipe
= basic_csc
->pipe
;
156 vs_consts
= pipe
->winsys
->buffer_map
159 basic_csc
->vs_const_buf
.buffer
,
160 PIPE_BUFFER_USAGE_CPU_WRITE
163 vs_consts
->dst_scale
.x
= destw
/ (float)basic_csc
->framebuffer
.cbufs
[0]->width
;
164 vs_consts
->dst_scale
.y
= desth
/ (float)basic_csc
->framebuffer
.cbufs
[0]->height
;
165 vs_consts
->dst_scale
.z
= 1;
166 vs_consts
->dst_scale
.w
= 1;
167 vs_consts
->dst_trans
.x
= destx
/ (float)basic_csc
->framebuffer
.cbufs
[0]->width
;
168 vs_consts
->dst_trans
.y
= desty
/ (float)basic_csc
->framebuffer
.cbufs
[0]->height
;
169 vs_consts
->dst_trans
.z
= 0;
170 vs_consts
->dst_trans
.w
= 0;
172 vs_consts
->src_scale
.x
= srcw
/ (float)surface
->texture
->width
[0];
173 vs_consts
->src_scale
.y
= srch
/ (float)surface
->texture
->height
[0];
174 vs_consts
->src_scale
.z
= 1;
175 vs_consts
->src_scale
.w
= 1;
176 vs_consts
->src_trans
.x
= srcx
/ (float)surface
->texture
->width
[0];
177 vs_consts
->src_trans
.y
= srcy
/ (float)surface
->texture
->height
[0];
178 vs_consts
->src_trans
.z
= 0;
179 vs_consts
->src_trans
.w
= 0;
181 pipe
->winsys
->buffer_unmap(pipe
->winsys
, basic_csc
->vs_const_buf
.buffer
);
183 pipe
->set_sampler_textures(pipe
, 1, &surface
->texture
);
184 pipe
->draw_arrays(pipe
, PIPE_PRIM_TRIANGLE_STRIP
, 0, 4);
199 static struct pipe_surface
* vlGetFrameBuffer
204 struct vlBasicCSC
*basic_csc
;
208 basic_csc
= (struct vlBasicCSC
*)csc
;
210 return basic_csc
->framebuffer
.cbufs
[0];
218 struct vlBasicCSC
*basic_csc
;
219 struct pipe_context
*pipe
;
224 basic_csc
= (struct vlBasicCSC
*)csc
;
225 pipe
= basic_csc
->pipe
;
227 if (basic_csc
->framebuffer_tex
)
228 pipe_texture_release(&basic_csc
->framebuffer_tex
);
230 pipe
->delete_sampler_state(pipe
, basic_csc
->sampler
);
231 pipe
->delete_vs_state(pipe
, basic_csc
->vertex_shader
);
232 pipe
->delete_fs_state(pipe
, basic_csc
->fragment_shader
);
234 for (i
= 0; i
< 2; ++i
)
235 pipe
->winsys
->buffer_destroy(pipe
->winsys
, basic_csc
->vertex_bufs
[i
].buffer
);
237 pipe
->winsys
->buffer_destroy(pipe
->winsys
, basic_csc
->vs_const_buf
.buffer
);
238 pipe
->winsys
->buffer_destroy(pipe
->winsys
, basic_csc
->fs_const_buf
.buffer
);
246 * Represents 2 triangles in a strip in normalized coords.
247 * Used to render the surface onto the frame buffer.
249 static const struct vlVertex2f surface_verts
[4] =
258 * Represents texcoords for the above. We can use the position values directly.
259 * TODO: Duplicate these in the shader, no need to create a buffer.
261 static const struct vlVertex2f
*surface_texcoords
= surface_verts
;
264 * Identity color conversion constants, for debugging
266 static const struct vlFragmentShaderConsts identity
=
269 0.0f
, 0.0f
, 0.0f
, 0.0f
272 1.0f
, 0.0f
, 0.0f
, 0.0f
,
273 0.0f
, 1.0f
, 0.0f
, 0.0f
,
274 0.0f
, 0.0f
, 1.0f
, 0.0f
,
275 0.0f
, 0.0f
, 0.0f
, 1.0f
280 * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
281 * Y is in [16,235], Cb and Cr are in [16,240]
282 * R, G, and B are in [16,235]
284 static const struct vlFragmentShaderConsts bt_601
=
287 0.0f
, 0.501960784f
, 0.501960784f
, 0.0f
290 1.0f
, 0.0f
, 1.371f
, 0.0f
,
291 1.0f
, -0.336f
, -0.698f
, 0.0f
,
292 1.0f
, 1.732f
, 0.0f
, 0.0f
,
293 0.0f
, 0.0f
, 0.0f
, 1.0f
298 * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
299 * Y is in [16,235], Cb and Cr are in [16,240]
300 * R, G, and B are in [0,255]
302 static const struct vlFragmentShaderConsts bt_601_full
=
305 0.062745098f
, 0.501960784f
, 0.501960784f
, 0.0f
308 1.164f
, 0.0f
, 1.596f
, 0.0f
,
309 1.164f
, -0.391f
, -0.813f
, 0.0f
,
310 1.164f
, 2.018f
, 0.0f
, 0.0f
,
311 0.0f
, 0.0f
, 0.0f
, 1.0f
316 * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
317 * Y is in [16,235], Cb and Cr are in [16,240]
318 * R, G, and B are in [16,235]
320 static const struct vlFragmentShaderConsts bt_709
=
323 0.0f
, 0.501960784f
, 0.501960784f
, 0.0f
326 1.0f
, 0.0f
, 1.540f
, 0.0f
,
327 1.0f
, -0.183f
, -0.459f
, 0.0f
,
328 1.0f
, 1.816f
, 0.0f
, 0.0f
,
329 0.0f
, 0.0f
, 0.0f
, 1.0f
334 * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
335 * Y is in [16,235], Cb and Cr are in [16,240]
336 * R, G, and B are in [0,255]
338 const struct vlFragmentShaderConsts bt_709_full
=
341 0.062745098f
, 0.501960784f
, 0.501960784f
, 0.0f
344 1.164f
, 0.0f
, 1.793f
, 0.0f
,
345 1.164f
, -0.213f
, -0.534f
, 0.0f
,
346 1.164f
, 2.115f
, 0.0f
, 0.0f
,
347 0.0f
, 0.0f
, 0.0f
, 1.0f
351 static int vlCreateVertexShader
353 struct vlBasicCSC
*csc
356 const unsigned int max_tokens
= 50;
358 struct pipe_context
*pipe
;
359 struct pipe_shader_state vs
;
360 struct tgsi_token
*tokens
;
361 struct tgsi_header
*header
;
363 struct tgsi_full_declaration decl
;
364 struct tgsi_full_instruction inst
;
372 tokens
= (struct tgsi_token
*)malloc(max_tokens
* sizeof(struct tgsi_token
));
375 *(struct tgsi_version
*)&tokens
[0] = tgsi_build_version();
377 header
= (struct tgsi_header
*)&tokens
[1];
378 *header
= tgsi_build_header();
380 *(struct tgsi_processor
*)&tokens
[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX
, header
);
385 * decl i0 ; Vertex pos
386 * decl i1 ; Vertex texcoords
388 for (i
= 0; i
< 2; i
++)
390 decl
= vl_decl_input(i
== 0 ? TGSI_SEMANTIC_POSITION
: TGSI_SEMANTIC_GENERIC
, i
, i
, i
);
391 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
395 * decl c0 ; Scaling vector to scale vertex pos rect to destination size
396 * decl c1 ; Translation vector to move vertex pos rect into position
397 * decl c2 ; Scaling vector to scale texcoord rect to source size
398 * decl c3 ; Translation vector to move texcoord rect into position
400 decl
= vl_decl_constants(TGSI_SEMANTIC_GENERIC
, 0, 0, 3);
401 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
404 * decl o0 ; Vertex pos
405 * decl o1 ; Vertex texcoords
407 for (i
= 0; i
< 2; i
++)
409 decl
= vl_decl_output(i
== 0 ? TGSI_SEMANTIC_POSITION
: TGSI_SEMANTIC_GENERIC
, i
, i
, i
);
410 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
414 decl
= vl_decl_temps(0, 1);
415 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
418 * madd o0, i0, c0, c1 ; Scale and translate unit output rect to destination size and pos
419 * madd o1, i1, c2, c3 ; Scale and translate unit texcoord rect to source size and pos
421 for (i
= 0; i
< 2; ++i
)
423 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);
424 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
429 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
432 csc
->vertex_shader
= pipe
->create_vs_state(pipe
, &vs
);
438 static int vlCreateFragmentShader
440 struct vlBasicCSC
*csc
443 const unsigned int max_tokens
= 50;
445 struct pipe_context
*pipe
;
446 struct pipe_shader_state fs
;
447 struct tgsi_token
*tokens
;
448 struct tgsi_header
*header
;
450 struct tgsi_full_declaration decl
;
451 struct tgsi_full_instruction inst
;
459 tokens
= (struct tgsi_token
*)malloc(max_tokens
* sizeof(struct tgsi_token
));
462 *(struct tgsi_version
*)&tokens
[0] = tgsi_build_version();
464 header
= (struct tgsi_header
*)&tokens
[1];
465 *header
= tgsi_build_header();
467 *(struct tgsi_processor
*)&tokens
[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT
, header
);
471 /* decl i0 ; Texcoords for s0 */
472 decl
= vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC
, 1, 0, 0, TGSI_INTERPOLATE_LINEAR
);
473 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
476 * decl c0 ; Bias vector for CSC
477 * decl c1-c4 ; CSC matrix c1-c4
479 decl
= vl_decl_constants(TGSI_SEMANTIC_GENERIC
, 0, 0, 4);
480 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
482 /* decl o0 ; Fragment color */
483 decl
= vl_decl_output(TGSI_SEMANTIC_COLOR
, 0, 0, 0);
484 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
487 decl
= vl_decl_temps(0, 0);
488 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
490 /* decl s0 ; Sampler for tex containing picture to display */
491 decl
= vl_decl_samplers(0, 0);
492 ti
+= tgsi_build_full_declaration(&decl
, &tokens
[ti
], header
, max_tokens
- ti
);
494 /* tex2d t0, i0, s0 ; Read src pixel */
495 inst
= vl_tex(TGSI_TEXTURE_2D
, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_INPUT
, 0, TGSI_FILE_SAMPLER
, 0);
496 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
498 /* sub t0, t0, c0 ; Subtract bias vector from pixel */
499 inst
= vl_inst3(TGSI_OPCODE_SUB
, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_CONSTANT
, 0);
500 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
503 * dp4 o0.x, t0, c1 ; Multiply pixel by the color conversion matrix
507 for (i
= 0; i
< 3; ++i
)
509 inst
= vl_inst3(TGSI_OPCODE_DP4
, TGSI_FILE_OUTPUT
, 0, TGSI_FILE_TEMPORARY
, 0, TGSI_FILE_CONSTANT
, i
+ 1);
510 inst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_X
<< i
;
511 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
516 ti
+= tgsi_build_full_instruction(&inst
, &tokens
[ti
], header
, max_tokens
- ti
);
519 csc
->fragment_shader
= pipe
->create_fs_state(pipe
, &fs
);
525 static int vlCreateDataBufs
527 struct vlBasicCSC
*csc
530 struct pipe_context
*pipe
;
537 * Create our vertex buffer and vertex buffer element
538 * VB contains 4 vertices that render a quad covering the entire window
539 * to display a rendered surface
540 * Quad is rendered as a tri strip
542 csc
->vertex_bufs
[0].pitch
= sizeof(struct vlVertex2f
);
543 csc
->vertex_bufs
[0].max_index
= 3;
544 csc
->vertex_bufs
[0].buffer_offset
= 0;
545 csc
->vertex_bufs
[0].buffer
= pipe
->winsys
->buffer_create
549 PIPE_BUFFER_USAGE_VERTEX
,
550 sizeof(struct vlVertex2f
) * 4
555 pipe
->winsys
->buffer_map(pipe
->winsys
, csc
->vertex_bufs
[0].buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
),
557 sizeof(struct vlVertex2f
) * 4
560 pipe
->winsys
->buffer_unmap(pipe
->winsys
, csc
->vertex_bufs
[0].buffer
);
562 csc
->vertex_elems
[0].src_offset
= 0;
563 csc
->vertex_elems
[0].vertex_buffer_index
= 0;
564 csc
->vertex_elems
[0].nr_components
= 2;
565 csc
->vertex_elems
[0].src_format
= PIPE_FORMAT_R32G32_FLOAT
;
568 * Create our texcoord buffer and texcoord buffer element
569 * Texcoord buffer contains the TCs for mapping the rendered surface to the 4 vertices
571 csc
->vertex_bufs
[1].pitch
= sizeof(struct vlVertex2f
);
572 csc
->vertex_bufs
[1].max_index
= 3;
573 csc
->vertex_bufs
[1].buffer_offset
= 0;
574 csc
->vertex_bufs
[1].buffer
= pipe
->winsys
->buffer_create
578 PIPE_BUFFER_USAGE_VERTEX
,
579 sizeof(struct vlVertex2f
) * 4
584 pipe
->winsys
->buffer_map(pipe
->winsys
, csc
->vertex_bufs
[1].buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
),
586 sizeof(struct vlVertex2f
) * 4
589 pipe
->winsys
->buffer_unmap(pipe
->winsys
, csc
->vertex_bufs
[1].buffer
);
591 csc
->vertex_elems
[1].src_offset
= 0;
592 csc
->vertex_elems
[1].vertex_buffer_index
= 1;
593 csc
->vertex_elems
[1].nr_components
= 2;
594 csc
->vertex_elems
[1].src_format
= PIPE_FORMAT_R32G32_FLOAT
;
597 * Create our vertex shader's constant buffer
598 * Const buffer contains scaling and translation vectors
600 csc
->vs_const_buf
.size
= sizeof(struct vlVertexShaderConsts
);
601 csc
->vs_const_buf
.buffer
= pipe
->winsys
->buffer_create
605 PIPE_BUFFER_USAGE_CONSTANT
,
606 csc
->vs_const_buf
.size
610 * Create our fragment shader's constant buffer
611 * Const buffer contains the color conversion matrix and bias vectors
613 csc
->fs_const_buf
.size
= sizeof(struct vlFragmentShaderConsts
);
614 csc
->fs_const_buf
.buffer
= pipe
->winsys
->buffer_create
618 PIPE_BUFFER_USAGE_CONSTANT
,
619 csc
->fs_const_buf
.size
623 * TODO: Refactor this into a seperate function,
624 * allow changing the CSC matrix at runtime to switch between regular & full versions
628 pipe
->winsys
->buffer_map(pipe
->winsys
, csc
->fs_const_buf
.buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
),
630 sizeof(struct vlFragmentShaderConsts
)
633 pipe
->winsys
->buffer_unmap(pipe
->winsys
, csc
->fs_const_buf
.buffer
);
640 struct vlBasicCSC
*csc
643 struct pipe_context
*pipe
;
644 struct pipe_sampler_state sampler
;
650 /* Delay creating the FB until vlPutPictureCSC() so we know window size */
651 csc
->framebuffer_tex
= NULL
;
652 csc
->framebuffer
.width
= 0;
653 csc
->framebuffer
.height
= 0;
654 csc
->framebuffer
.num_cbufs
= 1;
655 csc
->framebuffer
.cbufs
[0] = NULL
;
656 csc
->framebuffer
.zsbuf
= NULL
;
658 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
659 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
660 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
661 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
662 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
663 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
664 sampler
.compare_mode
= PIPE_TEX_COMPARE_NONE
;
665 sampler
.compare_func
= PIPE_FUNC_ALWAYS
;
666 sampler
.normalized_coords
= 1;
667 /*sampler.prefilter = ;*/
668 /*sampler.shadow_ambient = ;*/
669 /*sampler.lod_bias = ;*/
670 /*sampler.min_lod = ;*/
671 /*sampler.max_lod = ;*/
672 /*sampler.border_color[i] = ;*/
673 /*sampler.max_anisotropy = ;*/
674 csc
->sampler
= pipe
->create_sampler_state(pipe
, &sampler
);
676 vlCreateVertexShader(csc
);
677 vlCreateFragmentShader(csc
);
678 vlCreateDataBufs(csc
);
685 struct pipe_context
*pipe
,
689 struct vlBasicCSC
*basic_csc
;
694 basic_csc
= calloc(1, sizeof(struct vlBasicCSC
));
699 basic_csc
->base
.vlResizeFrameBuffer
= &vlResizeFrameBuffer
;
700 basic_csc
->base
.vlBegin
= &vlBegin
;
701 basic_csc
->base
.vlPutPicture
= &vlPutPictureCSC
;
702 basic_csc
->base
.vlEnd
= &vlEnd
;
703 basic_csc
->base
.vlGetFrameBuffer
= &vlGetFrameBuffer
;
704 basic_csc
->base
.vlDestroy
= &vlDestroy
;
705 basic_csc
->pipe
= pipe
;
709 *csc
= &basic_csc
->base
;