xa_renderer.c revision 9f2f5b3d7fd70663b98da5d302fcdfd5bc93db05
1/********************************************************** 2 * Copyright 2009-2011 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 ********************************************************* 25 * Authors: 26 * Zack Rusin <zackr-at-vmware-dot-com> 27 */ 28 29#include "xa_context.h" 30#include "xa_priv.h" 31#include <math.h> 32#include "cso_cache/cso_context.h" 33#include "util/u_inlines.h" 34#include "util/u_sampler.h" 35#include "util/u_draw_quad.h" 36 37#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y))) 38#define floatIsZero(x) (floatsEqual((x) + 1, 1)) 39 40#define NUM_COMPONENTS 4 41 42void 43 44 45renderer_set_constants(struct xa_context *r, 46 int shader_type, const float *params, int param_bytes); 47 48static INLINE boolean 49is_affine(float *matrix) 50{ 51 return floatIsZero(matrix[2]) && floatIsZero(matrix[5]) 52 && floatsEqual(matrix[8], 1); 53} 54 55static INLINE void 56map_point(float *mat, float x, float y, float *out_x, float *out_y) 57{ 58 if (!mat) { 59 *out_x = x; 60 *out_y = y; 61 return; 62 } 63 64 *out_x = mat[0] * x + mat[3] * y + mat[6]; 65 *out_y = mat[1] * x + mat[4] * y + mat[7]; 66 if (!is_affine(mat)) { 67 float w = 1 / (mat[2] * x + mat[5] * y + mat[8]); 68 69 *out_x *= w; 70 *out_y *= w; 71 } 72} 73 74static INLINE struct pipe_resource * 75renderer_buffer_create(struct xa_context *r) 76{ 77 struct pipe_resource *buf = pipe_user_buffer_create(r->pipe->screen, 78 r->buffer, 79 sizeof(float) * 80 r->buffer_size, 81 PIPE_BIND_VERTEX_BUFFER); 82 83 r->buffer_size = 0; 84 85 return buf; 86} 87 88static INLINE void 89renderer_draw(struct xa_context *r) 90{ 91 struct pipe_context *pipe = r->pipe; 92 struct pipe_resource *buf = 0; 93 int num_verts = r->buffer_size / (r->attrs_per_vertex * NUM_COMPONENTS); 94 95 if (!r->buffer_size) 96 return; 97 98 buf = renderer_buffer_create(r); 99 100 if (buf) { 101 cso_set_vertex_elements(r->cso, r->attrs_per_vertex, r->velems); 102 103 util_draw_vertex_buffer(pipe, r->cso, buf, 0, PIPE_PRIM_QUADS, num_verts, /* verts */ 104 r->attrs_per_vertex); /* attribs/vert */ 105 106 pipe_resource_reference(&buf, NULL); 107 } 108} 109 110static INLINE void 111renderer_draw_conditional(struct xa_context *r, int next_batch) 112{ 113 if (r->buffer_size + next_batch >= XA_VB_SIZE || 114 (next_batch == 0 && r->buffer_size)) { 115 renderer_draw(r); 116 } 117} 118 119void 120renderer_init_state(struct xa_context *r) 121{ 122 struct pipe_depth_stencil_alpha_state dsa; 123 struct pipe_rasterizer_state raster; 124 unsigned i; 125 126 /* set common initial clip state */ 127 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 128 cso_set_depth_stencil_alpha(r->cso, &dsa); 129 130 /* XXX: move to renderer_init_state? */ 131 memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); 132 raster.gl_rasterization_rules = 1; 133 cso_set_rasterizer(r->cso, &raster); 134 135 /* vertex elements state */ 136 memset(&r->velems[0], 0, sizeof(r->velems[0]) * 3); 137 for (i = 0; i < 3; i++) { 138 r->velems[i].src_offset = i * 4 * sizeof(float); 139 r->velems[i].instance_divisor = 0; 140 r->velems[i].vertex_buffer_index = 0; 141 r->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 142 } 143} 144 145static INLINE void 146add_vertex_color(struct xa_context *r, float x, float y, float color[4]) 147{ 148 float *vertex = r->buffer + r->buffer_size; 149 150 vertex[0] = x; 151 vertex[1] = y; 152 vertex[2] = 0.f; /*z */ 153 vertex[3] = 1.f; /*w */ 154 155 vertex[4] = color[0]; /*r */ 156 vertex[5] = color[1]; /*g */ 157 vertex[6] = color[2]; /*b */ 158 vertex[7] = color[3]; /*a */ 159 160 r->buffer_size += 8; 161} 162 163static INLINE void 164add_vertex_1tex(struct xa_context *r, float x, float y, float s, float t) 165{ 166 float *vertex = r->buffer + r->buffer_size; 167 168 vertex[0] = x; 169 vertex[1] = y; 170 vertex[2] = 0.f; /*z */ 171 vertex[3] = 1.f; /*w */ 172 173 vertex[4] = s; /*s */ 174 vertex[5] = t; /*t */ 175 vertex[6] = 0.f; /*r */ 176 vertex[7] = 1.f; /*q */ 177 178 r->buffer_size += 8; 179} 180 181static INLINE void 182add_vertex_2tex(struct xa_context *r, 183 float x, float y, float s0, float t0, float s1, float t1) 184{ 185 float *vertex = r->buffer + r->buffer_size; 186 187 vertex[0] = x; 188 vertex[1] = y; 189 vertex[2] = 0.f; /*z */ 190 vertex[3] = 1.f; /*w */ 191 192 vertex[4] = s0; /*s */ 193 vertex[5] = t0; /*t */ 194 vertex[6] = 0.f; /*r */ 195 vertex[7] = 1.f; /*q */ 196 197 vertex[8] = s1; /*s */ 198 vertex[9] = t1; /*t */ 199 vertex[10] = 0.f; /*r */ 200 vertex[11] = 1.f; /*q */ 201 202 r->buffer_size += 12; 203} 204 205static struct pipe_resource * 206setup_vertex_data_yuv(struct xa_context *r, 207 float srcX, 208 float srcY, 209 float srcW, 210 float srcH, 211 float dstX, 212 float dstY, 213 float dstW, float dstH, struct xa_surface *srf[]) 214{ 215 float s0, t0, s1, t1; 216 float spt0[2], spt1[2]; 217 struct pipe_resource *tex; 218 219 spt0[0] = srcX; 220 spt0[1] = srcY; 221 spt1[0] = srcX + srcW; 222 spt1[1] = srcY + srcH; 223 224 tex = srf[0]->tex; 225 s0 = spt0[0] / tex->width0; 226 t0 = spt0[1] / tex->height0; 227 s1 = spt1[0] / tex->width0; 228 t1 = spt1[1] / tex->height0; 229 230 /* 1st vertex */ 231 add_vertex_1tex(r, dstX, dstY, s0, t0); 232 /* 2nd vertex */ 233 add_vertex_1tex(r, dstX + dstW, dstY, s1, t0); 234 /* 3rd vertex */ 235 add_vertex_1tex(r, dstX + dstW, dstY + dstH, s1, t1); 236 /* 4th vertex */ 237 add_vertex_1tex(r, dstX, dstY + dstH, s0, t1); 238 239 return renderer_buffer_create(r); 240} 241 242/* Set up framebuffer, viewport and vertex shader constant buffer 243 * state for a particular destinaton surface. In all our rendering, 244 * these concepts are linked. 245 */ 246void 247renderer_bind_destination(struct xa_context *r, 248 struct pipe_surface *surface, int width, int height) 249{ 250 251 struct pipe_framebuffer_state fb; 252 struct pipe_viewport_state viewport; 253 254 /* Framebuffer uses actual surface width/height 255 */ 256 memset(&fb, 0, sizeof fb); 257 fb.width = surface->width; 258 fb.height = surface->height; 259 fb.nr_cbufs = 1; 260 fb.cbufs[0] = surface; 261 fb.zsbuf = 0; 262 263 /* Viewport just touches the bit we're interested in: 264 */ 265 viewport.scale[0] = width / 2.f; 266 viewport.scale[1] = height / 2.f; 267 viewport.scale[2] = 1.0; 268 viewport.scale[3] = 1.0; 269 viewport.translate[0] = width / 2.f; 270 viewport.translate[1] = height / 2.f; 271 viewport.translate[2] = 0.0; 272 viewport.translate[3] = 0.0; 273 274 /* Constant buffer set up to match viewport dimensions: 275 */ 276 if (r->fb_width != width || r->fb_height != height) { 277 float vs_consts[8] = { 278 2.f / width, 2.f / height, 1, 1, 279 -1, -1, 0, 0 280 }; 281 282 r->fb_width = width; 283 r->fb_height = height; 284 285 renderer_set_constants(r, PIPE_SHADER_VERTEX, 286 vs_consts, sizeof vs_consts); 287 } 288 289 cso_set_framebuffer(r->cso, &fb); 290 cso_set_viewport(r->cso, &viewport); 291} 292 293void 294renderer_set_constants(struct xa_context *r, 295 int shader_type, const float *params, int param_bytes) 296{ 297 struct pipe_resource **cbuf = 298 (shader_type == PIPE_SHADER_VERTEX) ? &r->vs_const_buffer : 299 &r->fs_const_buffer; 300 301 pipe_resource_reference(cbuf, NULL); 302 *cbuf = pipe_buffer_create(r->pipe->screen, 303 PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_STATIC, 304 param_bytes); 305 306 if (*cbuf) { 307 pipe_buffer_write(r->pipe, *cbuf, 0, param_bytes, params); 308 } 309 r->pipe->set_constant_buffer(r->pipe, shader_type, 0, *cbuf); 310} 311 312void 313renderer_copy_prepare(struct xa_context *r, 314 struct pipe_surface *dst_surface, 315 struct pipe_resource *src_texture) 316{ 317 struct pipe_context *pipe = r->pipe; 318 struct pipe_screen *screen = pipe->screen; 319 struct xa_shader shader; 320 321 assert(screen->is_format_supported(screen, dst_surface->format, 322 PIPE_TEXTURE_2D, 0, 323 PIPE_BIND_RENDER_TARGET)); 324 (void)screen; 325 326 /* set misc state we care about */ 327 { 328 struct pipe_blend_state blend; 329 330 memset(&blend, 0, sizeof(blend)); 331 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; 332 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; 333 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; 334 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; 335 blend.rt[0].colormask = PIPE_MASK_RGBA; 336 cso_set_blend(r->cso, &blend); 337 } 338 339 /* sampler */ 340 { 341 struct pipe_sampler_state sampler; 342 343 memset(&sampler, 0, sizeof(sampler)); 344 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 345 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 346 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 347 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 348 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; 349 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 350 sampler.normalized_coords = 1; 351 cso_single_sampler(r->cso, 0, &sampler); 352 cso_single_sampler_done(r->cso); 353 } 354 355 renderer_bind_destination(r, dst_surface, 356 dst_surface->width, dst_surface->height); 357 358 /* texture/sampler view */ 359 { 360 struct pipe_sampler_view templ; 361 struct pipe_sampler_view *src_view; 362 363 u_sampler_view_default_template(&templ, 364 src_texture, src_texture->format); 365 src_view = pipe->create_sampler_view(pipe, src_texture, &templ); 366 cso_set_fragment_sampler_views(r->cso, 1, &src_view); 367 pipe_sampler_view_reference(&src_view, NULL); 368 } 369 370 /* shaders */ 371 shader = xa_shaders_get(r->shaders, VS_COMPOSITE, FS_COMPOSITE); 372 cso_set_vertex_shader_handle(r->cso, shader.vs); 373 cso_set_fragment_shader_handle(r->cso, shader.fs); 374 375 r->buffer_size = 0; 376 r->attrs_per_vertex = 2; 377} 378 379void 380renderer_copy_pixmap(struct xa_context *r, 381 int dx, 382 int dy, 383 int sx, 384 int sy, 385 int width, int height, float src_width, float src_height) 386{ 387 float s0, t0, s1, t1; 388 float x0, y0, x1, y1; 389 390 /* XXX: could put the texcoord scaling calculation into the vertex 391 * shader. 392 */ 393 s0 = sx / src_width; 394 s1 = (sx + width) / src_width; 395 t0 = sy / src_height; 396 t1 = (sy + height) / src_height; 397 398 x0 = dx; 399 x1 = dx + width; 400 y0 = dy; 401 y1 = dy + height; 402 403 /* draw quad */ 404 renderer_draw_conditional(r, 4 * 8); 405 add_vertex_1tex(r, x0, y0, s0, t0); 406 add_vertex_1tex(r, x1, y0, s1, t0); 407 add_vertex_1tex(r, x1, y1, s1, t1); 408 add_vertex_1tex(r, x0, y1, s0, t1); 409} 410 411void 412renderer_draw_yuv(struct xa_context *r, 413 float src_x, 414 float src_y, 415 float src_w, 416 float src_h, 417 int dst_x, 418 int dst_y, int dst_w, int dst_h, struct xa_surface *srf[]) 419{ 420 struct pipe_context *pipe = r->pipe; 421 struct pipe_resource *buf = 0; 422 423 buf = setup_vertex_data_yuv(r, 424 src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, 425 dst_h, srf); 426 427 if (buf) { 428 const int num_attribs = 2; /*pos + tex coord */ 429 430 cso_set_vertex_elements(r->cso, num_attribs, r->velems); 431 432 util_draw_vertex_buffer(pipe, r->cso, buf, 0, PIPE_PRIM_QUADS, 4, /* verts */ 433 num_attribs); /* attribs/vert */ 434 435 pipe_resource_reference(&buf, NULL); 436 } 437} 438 439void 440renderer_begin_solid(struct xa_context *r) 441{ 442 r->buffer_size = 0; 443 r->attrs_per_vertex = 2; 444} 445 446void 447renderer_solid(struct xa_context *r, 448 int x0, int y0, int x1, int y1, float *color) 449{ 450 /* 451 * debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n", 452 * x0, y0, x1, y1, color[0], color[1], color[2], color[3]); */ 453 454 renderer_draw_conditional(r, 4 * 8); 455 456 /* 1st vertex */ 457 add_vertex_color(r, x0, y0, color); 458 /* 2nd vertex */ 459 add_vertex_color(r, x1, y0, color); 460 /* 3rd vertex */ 461 add_vertex_color(r, x1, y1, color); 462 /* 4th vertex */ 463 add_vertex_color(r, x0, y1, color); 464} 465 466void 467renderer_draw_flush(struct xa_context *r) 468{ 469 renderer_draw_conditional(r, 0); 470} 471