1/************************************************************************** 2 * 3 * Copyright 2010-2021 VMWare, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/** 29 * Look for common topology patterns which can be converted into rectangles. 30 */ 31 32 33#include "lp_setup_context.h" 34#include "draw/draw_vbuf.h" 35#include "draw/draw_vertex.h" 36#include "util/u_memory.h" 37#include "util/u_math.h" 38#include "lp_state_fs.h" 39#include "lp_state_setup.h" 40#include "lp_perf.h" 41 42 43/** 44 * Duplicated from lp_setup_vbuf.c. 45 */ 46typedef const float (*const_float4_ptr)[4]; 47 48 49static inline 50const_float4_ptr get_vert(const void *vertex_buffer, int index, int stride) 51{ 52 return (const_float4_ptr)((char *)vertex_buffer + index * stride); 53} 54 55 56/* Aero sends these weird zero area triangles. Test for them here. 57 */ 58static boolean 59is_zero_area(const float (*v0)[4], 60 const float (*v1)[4], 61 const float (*v2)[4]) 62{ 63 /* Specialized test for v0.y == v1.y == v2.y. 64 */ 65 return (v0[0][1] == v1[0][1] && 66 v0[0][1] == v2[0][1]); 67} 68 69 70/** 71 * Assuming axis-aligned stretch blit (s a function of x alone, t a 72 * function of y alone), create a new vertex as in: 73 * 74 * vx------+ 75 * | | 76 * | | 77 * out-----vy 78 */ 79static void 80make_vert(const float (*vx)[4], 81 const float (*vy)[4], 82 float (*out)[4]) 83{ 84 out[0][0] = vx[0][0]; 85 out[0][1] = vy[0][1]; 86 out[0][2] = vx[0][2]; 87 out[0][3] = vx[0][3]; 88 out[1][0] = vx[1][0]; 89 out[1][1] = vy[1][1]; 90} 91 92 93/* Calculate axis-aligned interpolant for s as a function of x. 94 */ 95static void 96calc_interps(float x0, float x1, 97 float s0, float s1, 98 float *a, float *b) 99{ 100 assert(x0 != x1); 101 *a = (s0 - s1) / (x0 - x1); 102 *b = s0 - *a * x0; 103} 104 105 106/* Validate axis-aligned interpolant for s and t as functions of x and 107 * y respectively. 108 */ 109static boolean 110test_interps(const_float4_ptr v, 111 float as, float bs, 112 float at, float bt) 113{ 114 float s = as * v[0][0] + bs; 115 float t = at * v[0][1] + bt; 116 return (util_is_approx(s, v[1][0], 1/4096.0) && 117 util_is_approx(t, v[1][1], 1/4096.0)); 118} 119 120 121static void 122rect(struct lp_setup_context *setup, 123 const float (*v0)[4], 124 const float (*v1)[4], 125 const float (*v2)[4]) 126{ 127 ASSERTED int culled = LP_COUNT_GET(nr_culled_rects); 128 129 if (0) { 130 float as, bs, at, bt; 131 calc_interps(v0[0][0], v2[0][0], v0[1][0], v2[1][0], &as, &bs); 132 calc_interps(v0[0][1], v2[0][1], v0[1][1], v2[1][1], &at, &bt); 133 assert(test_interps(v1, as, bs, at, bt)); 134 } 135 136 assert(v0[0][0] == v1[0][0]); 137 assert(v1[0][1] == v2[0][1]); 138 139 lp_rect_cw(setup, v0, v1, v2, TRUE); 140 141 assert(culled == LP_COUNT_GET(nr_culled_rects)); 142} 143 144 145/** 146 * Check this is an axis-aligned rectangle as in: 147 * 148 * v3------v0 149 * | | 150 * | | 151 * v2------v1 152 */ 153static boolean 154test_rect(const_float4_ptr v0, 155 const_float4_ptr v1, 156 const_float4_ptr v2, 157 const_float4_ptr v3) 158{ 159 if (v0[0][0] != v1[0][0] || 160 v1[0][1] != v2[0][1] || 161 v2[0][0] != v3[0][0] || 162 v3[0][1] != v0[0][1]) 163 return FALSE; 164 165 if (v0[0][3] != 1.0 || 166 v1[0][3] != 1.0 || 167 v2[0][3] != 1.0 || 168 v3[0][3] != 1.0) 169 return FALSE; 170 171 return TRUE; 172} 173 174 175/** 176 * Aero sends the following shape as 177 * 178 * 18 12 179 * +-------------------------------------------------/----+ 180 * |\ /--------- /| 181 * | \ /--------- / | 182 * | \ /--------- / | 183 * | \ /--------- / | 184 * vA + +--------------------------------------------+ + vC 185 * | | 9 6 | | 186 * | /| |\ | 187 * | || || | 188 * | / | | \ | 189 * | | | | | | 190 * | | | 3 0 | \ | 191 * vB + / +--------------------------------------------+ | + vD 192 * | | / ---------/ \ | | 193 * |/ / ---------/ \ \| 194 * ||/ ---------/ \|| 195 * |/ ---------/ \| 196 * +----/-------------------------------------------------+ 197 * 1 2 198 * 199 * and in the following decomposition: 200 * (0, 1, 2) 201 * (3, 0, 1), 202 * (6, 0, 2), 203 * (9, 3, 1), 204 * (12, 2, 6), 205 * (12, 6, 9), 206 * (18, 1, 9), 207 * (18, 9, 12), 208 * 209 * There's no straight-forward way to interpret the existing vertices 210 * as rectangles. Instead we convert this into four axis-aligned 211 * rectangles by introducing new vertices at vA, vB, vC and vD, and 212 * then drawing rectangles. 213 */ 214static boolean 215check_elts24(struct lp_setup_context *setup, const void *vb, int stride) 216{ 217 const int count = 24; 218 const int uniq[8] = { 0, 1, 2, 3, 6, 9, 12, 18 }; 219 const int elts[24] = { 220 0, 1, 2, 221 3, 0, 1, 222 6, 0, 2, 223 9, 3, 1, 224 12, 2, 6, 225 12, 6, 9, 226 18, 1, 9, 227 18, 9, 12 228 }; 229 const_float4_ptr v0 = get_vert(vb, stride, 0); 230 const_float4_ptr v1 = get_vert(vb, stride, 1); 231 const_float4_ptr v2 = get_vert(vb, stride, 2); 232 const_float4_ptr v3 = get_vert(vb, stride, 3); 233 const_float4_ptr v6 = get_vert(vb, stride, 6); 234 const_float4_ptr v9 = get_vert(vb, stride, 9); 235 const_float4_ptr v12 = get_vert(vb, stride, 12); 236 const_float4_ptr v18 = get_vert(vb, stride, 18); 237 238 /* Could just calculate a set of interpolants and bin rectangle 239 * commands for this triangle list directly. Instead, introduce 240 * some new vertices and feed to the rectangle setup code: 241 */ 242 PIPE_ALIGN_VAR(16) float vA[2][4]; 243 PIPE_ALIGN_VAR(16) float vB[2][4]; 244 PIPE_ALIGN_VAR(16) float vC[2][4]; 245 PIPE_ALIGN_VAR(16) float vD[2][4]; 246 247 float as, bs; 248 float at, bt; 249 int i; 250 251 if (stride != 32) 252 return FALSE; 253 254 /* Check the shape is two rectangles: 255 */ 256 if (!test_rect(v12, v2, v1, v18)) 257 return FALSE; 258 259 if (!test_rect(v6, v0, v3, v9)) 260 return FALSE; 261 262 /* XXX: check one rect is inside the other? 263 */ 264 265 /* Check our tesselation matches: 266 */ 267 for (i = 0; i < count; i++) { 268 if (memcmp(get_vert(vb, i, stride), 269 get_vert(vb, elts[i], stride), 270 6 * sizeof(float)) != 0) 271 return FALSE; 272 } 273 274 /* Test that this is a stretch blit, meaning we should be able to 275 * introduce vertices at will. 276 */ 277 calc_interps(v0[0][0], v2[0][0], v0[1][0], v2[1][0], &as, &bs); 278 calc_interps(v0[0][1], v2[0][1], v0[1][1], v2[1][1], &at, &bt); 279 280 for (i = 0; i < ARRAY_SIZE(uniq); i++) { 281 const_float4_ptr v = get_vert(vb, stride, i); 282 if (!test_interps(v, as, bs, at, bt)) 283 return FALSE; 284 } 285 286 make_vert(v18, v9, vA); 287 make_vert(v18, v3, vB); 288 make_vert(v12, v9, vC); 289 make_vert(v12, v3, vD); 290 291 assert(test_interps((const_float4_ptr)vA, as, bs, at, bt)); 292 assert(test_interps((const_float4_ptr)vB, as, bs, at, bt)); 293 assert(test_interps((const_float4_ptr)vC, as, bs, at, bt)); 294 assert(test_interps((const_float4_ptr)vD, as, bs, at, bt)); 295 296 rect(setup, 297 (const_float4_ptr)v12, 298 (const_float4_ptr)vC, 299 (const_float4_ptr)vA); 300 301 rect(setup, 302 (const_float4_ptr)v9, 303 (const_float4_ptr)v3, 304 (const_float4_ptr)vB); 305 306 rect(setup, 307 (const_float4_ptr)vD, 308 (const_float4_ptr)v2, 309 (const_float4_ptr)v1); 310 311 rect(setup, 312 (const_float4_ptr)vC, 313 (const_float4_ptr)vD, 314 (const_float4_ptr)v0); 315 316 return TRUE; 317} 318 319boolean 320lp_setup_analyse_triangles(struct lp_setup_context *setup, 321 const void *vb, 322 int stride, 323 int nr) 324{ 325 int i; 326 const boolean variant_blit = setup->fs.current.variant->blit; 327 328 if (0) { 329 debug_printf("%s %d\n", __FUNCTION__, nr); 330 331 if (variant_blit) { 332 debug_printf(" - blit variant\n"); 333 } 334 335 for (i = 0; i < nr; i += 3) { 336 const_float4_ptr v0 = get_vert(vb, i, stride); 337 const_float4_ptr v1 = get_vert(vb, i+1, stride); 338 const_float4_ptr v2 = get_vert(vb, i+2, stride); 339 lp_setup_print_triangle(setup, v0, v1, v2); 340 } 341 } 342 343 /* When drawing some window navigator bars, aero sends a mixed up 344 * rectangle: 345 * 346 * - first triangle ccw 347 * - second triangle cw 348 * - third triangle zero area. 349 */ 350 if (nr == 9 && 351 is_zero_area(get_vert(vb, nr-1, stride), 352 get_vert(vb, nr-2, stride), 353 get_vert(vb, nr-3, stride))) 354 { 355 const float (*v0)[4] = get_vert(vb, 0, stride); 356 const float (*v1)[4] = get_vert(vb, 1, stride); 357 const float (*v2)[4] = get_vert(vb, 2, stride); 358 const float (*v3)[4] = get_vert(vb, 3, stride); 359 const float (*v4)[4] = get_vert(vb, 4, stride); 360 const float (*v5)[4] = get_vert(vb, 5, stride); 361 362 /* 363 * [ v0, v1, v2 ] [ v3, v4, v5 ] 364 * [(X0, Y0), (X0, Y1), (X1, Y1)] [(X1, Y0), (X1, Y1), (X0, Y0)] 365 */ 366 if (v0[0][0] == v1[0][0] && v0[0][0] == v5[0][0] && 367 v2[0][0] == v3[0][0] && v2[0][0] == v4[0][0] && 368 v0[0][1] == v3[0][1] && v0[0][1] == v5[0][1] && 369 v1[0][1] == v2[0][1] && v1[0][1] == v4[0][1]) { 370 371 lp_rect_cw(setup, v0, v1, v2, TRUE); 372 } 373 return TRUE; 374 } 375 376 /* When highlighting (?) windows, aero sends a window border 377 * comprised of non-rectangular triangles, but which as a whole can 378 * be decomposed into rectangles. 379 * 380 * Again, with a zero-area trailing triangle. 381 * 382 * This requires introducing a couple of new vertices, which are 383 * luckily easy to compute. 384 */ 385 if (nr == 27 && 386 variant_blit && 387 setup->setup.variant->key.inputs[0].src_index == 1 && 388 setup->setup.variant->key.inputs[0].usage_mask == 0x3 && 389 is_zero_area(get_vert(vb, nr-1, stride), 390 get_vert(vb, nr-2, stride), 391 get_vert(vb, nr-3, stride)) && 392 check_elts24(setup, vb, stride)) 393 { 394 return TRUE; 395 } 396 397 return FALSE; 398} 399