vg_context.c revision e8bbaff22e75953b1c8a259753dbd8658998305e
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 48struct vg_context *_vg_context = 0; 49 50struct vg_context * vg_current_context(void) 51{ 52 return _vg_context; 53} 54 55static 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 */ 71static boolean 72choose_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 93void vg_set_current_context(struct vg_context *ctx) 94{ 95 _vg_context = ctx; 96 api_make_dispatch_current((ctx) ? ctx->dispatch : NULL); 97} 98 99struct 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 168void 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 228void 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 234VGboolean 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 247void 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 259void 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 271static 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 345void 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 453VGboolean 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 462void 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 473void 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 512void 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 546void * 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 559void * 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 571void * 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 583void 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} 600