Merge branch 'lp-offset-twoside'
[mesa.git] / src / gallium / state_trackers / vega / vg_context.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27 #include "vg_context.h"
28
29 #include "paint.h"
30 #include "renderer.h"
31 #include "shaders_cache.h"
32 #include "shader.h"
33 #include "asm_util.h"
34 #include "st_inlines.h"
35 #include "vg_manager.h"
36 #include "api.h"
37
38 #include "pipe/p_context.h"
39 #include "util/u_inlines.h"
40
41 #include "cso_cache/cso_context.h"
42
43 #include "util/u_simple_shaders.h"
44 #include "util/u_memory.h"
45 #include "util/u_blit.h"
46 #include "util/u_sampler.h"
47
48 struct vg_context *_vg_context = 0;
49
50 struct vg_context * vg_current_context(void)
51 {
52 return _vg_context;
53 }
54
55 static void init_clear(struct vg_context *st)
56 {
57 struct pipe_context *pipe = st->pipe;
58
59 /* rasterizer state: bypass clipping */
60 memset(&st->clear.raster, 0, sizeof(st->clear.raster));
61 st->clear.raster.gl_rasterization_rules = 1;
62
63 /* fragment shader state: color pass-through program */
64 st->clear.fs =
65 util_make_fragment_passthrough_shader(pipe);
66 }
67
68 /**
69 * A depth/stencil rb will be needed regardless of what the visual says.
70 */
71 static boolean
72 choose_depth_stencil_format(struct vg_context *ctx)
73 {
74 struct pipe_screen *screen = ctx->pipe->screen;
75 enum pipe_format formats[] = {
76 PIPE_FORMAT_Z24_UNORM_S8_USCALED,
77 PIPE_FORMAT_S8_USCALED_Z24_UNORM,
78 PIPE_FORMAT_NONE
79 };
80 enum pipe_format *fmt;
81
82 for (fmt = formats; *fmt != PIPE_FORMAT_NONE; fmt++) {
83 if (screen->is_format_supported(screen, *fmt,
84 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0))
85 break;
86 }
87
88 ctx->ds_format = *fmt;
89
90 return (ctx->ds_format != PIPE_FORMAT_NONE);
91 }
92
93 void vg_set_current_context(struct vg_context *ctx)
94 {
95 _vg_context = ctx;
96 api_make_dispatch_current((ctx) ? ctx->dispatch : NULL);
97 }
98
99 struct vg_context * vg_create_context(struct pipe_context *pipe,
100 const void *visual,
101 struct vg_context *share)
102 {
103 struct vg_context *ctx;
104 unsigned i;
105
106 ctx = CALLOC_STRUCT(vg_context);
107
108 ctx->pipe = pipe;
109 if (!choose_depth_stencil_format(ctx)) {
110 FREE(ctx);
111 return NULL;
112 }
113
114 ctx->dispatch = api_create_dispatch();
115
116 vg_init_state(&ctx->state.vg);
117 ctx->state.dirty = ALL_DIRTY;
118
119 ctx->cso_context = cso_create_context(pipe);
120
121 init_clear(ctx);
122
123 ctx->default_paint = paint_create(ctx);
124 ctx->state.vg.stroke_paint = ctx->default_paint;
125 ctx->state.vg.fill_paint = ctx->default_paint;
126
127
128 ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
129 ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
130 ctx->mask.sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
131 ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
132 ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
133 ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
134 ctx->mask.sampler.normalized_coords = 0;
135
136 ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
137 ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
138 ctx->blend_sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
139 ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
140 ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
141 ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
142 ctx->blend_sampler.normalized_coords = 0;
143
144 for (i = 0; i < 2; i++) {
145 ctx->velems[i].src_offset = i * 4 * sizeof(float);
146 ctx->velems[i].instance_divisor = 0;
147 ctx->velems[i].vertex_buffer_index = 0;
148 ctx->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
149 }
150
151 vg_set_error(ctx, VG_NO_ERROR);
152
153 ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create();
154 ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create();
155 ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create();
156 ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create();
157 ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create();
158
159 ctx->renderer = renderer_create(ctx);
160 ctx->sc = shaders_cache_create(ctx);
161 ctx->shader = shader_create(ctx);
162
163 ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context);
164
165 return ctx;
166 }
167
168 void vg_destroy_context(struct vg_context *ctx)
169 {
170 struct pipe_resource **cbuf = &ctx->mask.cbuf;
171 struct pipe_resource **vsbuf = &ctx->vs_const_buffer;
172
173 util_destroy_blit(ctx->blit);
174 renderer_destroy(ctx->renderer);
175 shaders_cache_destroy(ctx->sc);
176 shader_destroy(ctx->shader);
177 paint_destroy(ctx->default_paint);
178
179 if (*cbuf)
180 pipe_resource_reference(cbuf, NULL);
181
182 if (*vsbuf)
183 pipe_resource_reference(vsbuf, NULL);
184
185 if (ctx->clear.fs) {
186 cso_delete_fragment_shader(ctx->cso_context, ctx->clear.fs);
187 ctx->clear.fs = NULL;
188 }
189
190 if (ctx->plain_vs) {
191 vg_shader_destroy(ctx, ctx->plain_vs);
192 ctx->plain_vs = NULL;
193 }
194 if (ctx->clear_vs) {
195 vg_shader_destroy(ctx, ctx->clear_vs);
196 ctx->clear_vs = NULL;
197 }
198 if (ctx->texture_vs) {
199 vg_shader_destroy(ctx, ctx->texture_vs);
200 ctx->texture_vs = NULL;
201 }
202
203 if (ctx->pass_through_depth_fs)
204 vg_shader_destroy(ctx, ctx->pass_through_depth_fs);
205 if (ctx->mask.union_fs)
206 vg_shader_destroy(ctx, ctx->mask.union_fs);
207 if (ctx->mask.intersect_fs)
208 vg_shader_destroy(ctx, ctx->mask.intersect_fs);
209 if (ctx->mask.subtract_fs)
210 vg_shader_destroy(ctx, ctx->mask.subtract_fs);
211 if (ctx->mask.set_fs)
212 vg_shader_destroy(ctx, ctx->mask.set_fs);
213
214 cso_release_all(ctx->cso_context);
215 cso_destroy_context(ctx->cso_context);
216
217 cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]);
218 cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]);
219 cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]);
220 cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]);
221 cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]);
222
223 api_destroy_dispatch(ctx->dispatch);
224
225 FREE(ctx);
226 }
227
228 void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type)
229 {
230 obj->type = type;
231 obj->ctx = ctx;
232 }
233
234 VGboolean vg_context_is_object_valid(struct vg_context *ctx,
235 enum vg_object_type type,
236 void *ptr)
237 {
238 if (ctx) {
239 struct cso_hash *hash = ctx->owned_objects[type];
240 if (!hash)
241 return VG_FALSE;
242 return cso_hash_contains(hash, (unsigned)(long)ptr);
243 }
244 return VG_FALSE;
245 }
246
247 void vg_context_add_object(struct vg_context *ctx,
248 enum vg_object_type type,
249 void *ptr)
250 {
251 if (ctx) {
252 struct cso_hash *hash = ctx->owned_objects[type];
253 if (!hash)
254 return;
255 cso_hash_insert(hash, (unsigned)(long)ptr, ptr);
256 }
257 }
258
259 void vg_context_remove_object(struct vg_context *ctx,
260 enum vg_object_type type,
261 void *ptr)
262 {
263 if (ctx) {
264 struct cso_hash *hash = ctx->owned_objects[type];
265 if (!hash)
266 return;
267 cso_hash_take(hash, (unsigned)(long)ptr);
268 }
269 }
270
271 static void update_clip_state(struct vg_context *ctx)
272 {
273 struct pipe_depth_stencil_alpha_state *dsa = &ctx->state.g3d.dsa;
274 struct vg_state *state = &ctx->state.vg;
275
276 memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
277
278 if (state->scissoring) {
279 struct pipe_blend_state *blend = &ctx->state.g3d.blend;
280 struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
281 int i;
282
283 dsa->depth.writemask = 1;/*glDepthMask(TRUE);*/
284 dsa->depth.func = PIPE_FUNC_ALWAYS;
285 dsa->depth.enabled = 1;
286
287 cso_save_blend(ctx->cso_context);
288 cso_save_fragment_shader(ctx->cso_context);
289 /* set a passthrough shader */
290 if (!ctx->pass_through_depth_fs)
291 ctx->pass_through_depth_fs = shader_create_from_text(ctx->pipe,
292 pass_through_depth_asm,
293 40,
294 PIPE_SHADER_FRAGMENT);
295 cso_set_fragment_shader_handle(ctx->cso_context,
296 ctx->pass_through_depth_fs->driver);
297 cso_set_depth_stencil_alpha(ctx->cso_context, dsa);
298
299 ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0, 0);
300
301 /* disable color writes */
302 blend->rt[0].colormask = 0; /*disable colorwrites*/
303 cso_set_blend(ctx->cso_context, blend);
304
305 /* enable scissoring */
306 for (i = 0; i < state->scissor_rects_num; ++i) {
307 const float x = state->scissor_rects[i * 4 + 0].f;
308 const float y = state->scissor_rects[i * 4 + 1].f;
309 const float width = state->scissor_rects[i * 4 + 2].f;
310 const float height = state->scissor_rects[i * 4 + 3].f;
311 VGfloat minx, miny, maxx, maxy;
312
313 minx = 0;
314 miny = 0;
315 maxx = fb->width;
316 maxy = fb->height;
317
318 if (x > minx)
319 minx = x;
320 if (y > miny)
321 miny = y;
322
323 if (x + width < maxx)
324 maxx = x + width;
325 if (y + height < maxy)
326 maxy = y + height;
327
328 /* check for null space */
329 if (minx >= maxx || miny >= maxy)
330 minx = miny = maxx = maxy = 0;
331
332 /*glClear(GL_DEPTH_BUFFER_BIT);*/
333 renderer_draw_quad(ctx->renderer, minx, miny, maxx, maxy, 0.0f);
334 }
335
336 cso_restore_blend(ctx->cso_context);
337 cso_restore_fragment_shader(ctx->cso_context);
338
339 dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */
340 dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/
341 dsa->depth.func = PIPE_FUNC_GEQUAL;
342 }
343 }
344
345 void vg_validate_state(struct vg_context *ctx)
346 {
347 vg_manager_validate_framebuffer(ctx);
348
349 if ((ctx->state.dirty & BLEND_DIRTY)) {
350 struct pipe_blend_state *blend = &ctx->state.g3d.blend;
351 memset(blend, 0, sizeof(struct pipe_blend_state));
352 blend->rt[0].blend_enable = 1;
353 blend->rt[0].colormask = PIPE_MASK_RGBA;
354
355 switch (ctx->state.vg.blend_mode) {
356 case VG_BLEND_SRC:
357 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
358 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
359 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
360 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
361 blend->rt[0].blend_enable = 0;
362 break;
363 case VG_BLEND_SRC_OVER:
364 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
365 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
366 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
367 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
368 break;
369 case VG_BLEND_DST_OVER:
370 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
371 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
372 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
373 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
374 break;
375 case VG_BLEND_SRC_IN:
376 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
377 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
378 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
379 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
380 break;
381 case VG_BLEND_DST_IN:
382 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ZERO;
383 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
384 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
385 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
386 break;
387 case VG_BLEND_MULTIPLY:
388 case VG_BLEND_SCREEN:
389 case VG_BLEND_DARKEN:
390 case VG_BLEND_LIGHTEN:
391 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
392 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
393 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
394 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
395 blend->rt[0].blend_enable = 0;
396 break;
397 case VG_BLEND_ADDITIVE:
398 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
399 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
400 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
401 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
402 break;
403 default:
404 assert(!"not implemented blend mode");
405 }
406 cso_set_blend(ctx->cso_context, &ctx->state.g3d.blend);
407 }
408 if ((ctx->state.dirty & RASTERIZER_DIRTY)) {
409 struct pipe_rasterizer_state *raster = &ctx->state.g3d.rasterizer;
410 memset(raster, 0, sizeof(struct pipe_rasterizer_state));
411 raster->gl_rasterization_rules = 1;
412 cso_set_rasterizer(ctx->cso_context, &ctx->state.g3d.rasterizer);
413 }
414 if ((ctx->state.dirty & VIEWPORT_DIRTY)) {
415 struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
416 const VGint param_bytes = 8 * sizeof(VGfloat);
417 VGfloat vs_consts[8] = {
418 2.f/fb->width, 2.f/fb->height, 1, 1,
419 -1, -1, 0, 0
420 };
421 struct pipe_resource **cbuf = &ctx->vs_const_buffer;
422
423 vg_set_viewport(ctx, VEGA_Y0_BOTTOM);
424
425 pipe_resource_reference(cbuf, NULL);
426 *cbuf = pipe_buffer_create(ctx->pipe->screen,
427 PIPE_BIND_CONSTANT_BUFFER,
428 param_bytes);
429
430 if (*cbuf) {
431 st_no_flush_pipe_buffer_write(ctx, *cbuf,
432 0, param_bytes, vs_consts);
433 }
434 ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, *cbuf);
435 }
436 if ((ctx->state.dirty & VS_DIRTY)) {
437 cso_set_vertex_shader_handle(ctx->cso_context,
438 vg_plain_vs(ctx));
439 }
440
441 /* must be last because it renders to the depth buffer*/
442 if ((ctx->state.dirty & DEPTH_STENCIL_DIRTY)) {
443 update_clip_state(ctx);
444 cso_set_depth_stencil_alpha(ctx->cso_context, &ctx->state.g3d.dsa);
445 }
446
447 shader_set_masking(ctx->shader, ctx->state.vg.masking);
448 shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
449
450 ctx->state.dirty = NONE_DIRTY;
451 }
452
453 VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type)
454 {
455 struct vg_object *obj = ptr;
456 if (ptr && is_aligned(obj) && obj->type == type)
457 return VG_TRUE;
458 else
459 return VG_FALSE;
460 }
461
462 void vg_set_error(struct vg_context *ctx,
463 VGErrorCode code)
464 {
465 /*vgGetError returns the oldest error code provided by
466 * an API call on the current context since the previous
467 * call to vgGetError on that context (or since the creation
468 of the context).*/
469 if (ctx->_error == VG_NO_ERROR)
470 ctx->_error = code;
471 }
472
473 void vg_prepare_blend_surface(struct vg_context *ctx)
474 {
475 struct pipe_surface *dest_surface = NULL;
476 struct pipe_context *pipe = ctx->pipe;
477 struct pipe_sampler_view *view;
478 struct pipe_sampler_view view_templ;
479 struct st_framebuffer *stfb = ctx->draw_buffer;
480 struct st_renderbuffer *strb = stfb->strb;
481
482 /* first finish all pending rendering */
483 vgFinish();
484
485 u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format);
486 view = pipe->create_sampler_view(pipe, strb->texture, &view_templ);
487
488 dest_surface = pipe->screen->get_tex_surface(pipe->screen,
489 stfb->blend_texture_view->texture,
490 0, 0, 0,
491 PIPE_BIND_RENDER_TARGET);
492 /* flip it, because we want to use it as a sampler */
493 util_blit_pixels_tex(ctx->blit,
494 view,
495 0, strb->height,
496 strb->width, 0,
497 dest_surface,
498 0, 0,
499 strb->width, strb->height,
500 0.0, PIPE_TEX_MIPFILTER_NEAREST);
501
502 if (dest_surface)
503 pipe_surface_reference(&dest_surface, NULL);
504
505 /* make sure it's complete */
506 vgFinish();
507
508 pipe_sampler_view_reference(&view, NULL);
509 }
510
511
512 void vg_prepare_blend_surface_from_mask(struct vg_context *ctx)
513 {
514 struct pipe_surface *dest_surface = NULL;
515 struct pipe_context *pipe = ctx->pipe;
516 struct st_framebuffer *stfb = ctx->draw_buffer;
517 struct st_renderbuffer *strb = stfb->strb;
518
519 vg_validate_state(ctx);
520
521 /* first finish all pending rendering */
522 vgFinish();
523
524 dest_surface = pipe->screen->get_tex_surface(pipe->screen,
525 stfb->blend_texture_view->texture,
526 0, 0, 0,
527 PIPE_BIND_RENDER_TARGET);
528
529 /* flip it, because we want to use it as a sampler */
530 util_blit_pixels_tex(ctx->blit,
531 stfb->alpha_mask_view,
532 0, strb->height,
533 strb->width, 0,
534 dest_surface,
535 0, 0,
536 strb->width, strb->height,
537 0.0, PIPE_TEX_MIPFILTER_NEAREST);
538
539 /* make sure it's complete */
540 vgFinish();
541
542 if (dest_surface)
543 pipe_surface_reference(&dest_surface, NULL);
544 }
545
546 void * vg_plain_vs(struct vg_context *ctx)
547 {
548 if (!ctx->plain_vs) {
549 ctx->plain_vs = shader_create_from_text(ctx->pipe,
550 vs_plain_asm,
551 200,
552 PIPE_SHADER_VERTEX);
553 }
554
555 return ctx->plain_vs->driver;
556 }
557
558
559 void * vg_clear_vs(struct vg_context *ctx)
560 {
561 if (!ctx->clear_vs) {
562 ctx->clear_vs = shader_create_from_text(ctx->pipe,
563 vs_clear_asm,
564 200,
565 PIPE_SHADER_VERTEX);
566 }
567
568 return ctx->clear_vs->driver;
569 }
570
571 void * vg_texture_vs(struct vg_context *ctx)
572 {
573 if (!ctx->texture_vs) {
574 ctx->texture_vs = shader_create_from_text(ctx->pipe,
575 vs_texture_asm,
576 200,
577 PIPE_SHADER_VERTEX);
578 }
579
580 return ctx->texture_vs->driver;
581 }
582
583 void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation)
584 {
585 struct pipe_viewport_state viewport;
586 struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
587 VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f;
588
589 viewport.scale[0] = fb->width / 2.f;
590 viewport.scale[1] = fb->height / y_scale;
591 viewport.scale[2] = 1.0;
592 viewport.scale[3] = 1.0;
593 viewport.translate[0] = fb->width / 2.f;
594 viewport.translate[1] = fb->height / 2.f;
595 viewport.translate[2] = 0.0;
596 viewport.translate[3] = 0.0;
597
598 cso_set_viewport(ctx->cso_context, &viewport);
599 }