1/* 2 * Copyright 2011 VMWare, Inc. 3 * 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 TUNGSTEN GRAPHICS 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 * Author: Thomas Hellstrom <thellstrom@vmware.com> 26 */ 27#ifdef _HAVE_CONFIG_H_ 28#include "config.h" 29#endif 30 31#include <xorg-server.h> 32#include "vmwgfx_saa_priv.h" 33 34 35static const enum xa_surface_type vmwgfx_stype_map[] = { 36 [PICT_TYPE_OTHER] = xa_type_other, 37 [PICT_TYPE_A] = xa_type_a, 38 [PICT_TYPE_ARGB] = xa_type_argb, 39 [PICT_TYPE_ABGR] = xa_type_abgr, 40 [PICT_TYPE_BGRA] = xa_type_bgra 41}; 42 43static const unsigned int vmwgfx_stype_map_size = 44 sizeof(vmwgfx_stype_map) / sizeof(enum xa_surface_type); 45 46/** 47 * vmwgfx_xa_surface_redefine - wrapper around xa_surface_redefine 48 * 49 * @vpix: Pointer to the struct vmwgfx_saa_pixmap the surface is attached to. 50 * @srf: The surface. 51 * @width: New width. 52 * @height: New height. 53 * @depth: New pixel depth. 54 * @stype: New surface type. 55 * @rgb_format: New rgb format. 56 * @new_flags: New surface flags. 57 * @copy_contents: Copy contents if new backing store is allocated. 58 * 59 * This is a wrapper that prints out an error message if the backing store 60 * of an active scanout surface is changed. 61 */ 62Bool 63vmwgfx_xa_surface_redefine(struct vmwgfx_saa_pixmap *vpix, 64 struct xa_surface *srf, 65 int width, 66 int height, 67 int depth, 68 enum xa_surface_type stype, 69 enum xa_formats rgb_format, 70 unsigned int new_flags, 71 int copy_contents) 72{ 73 uint32_t handle, new_handle, dummy; 74 Bool have_handle = FALSE; 75 76 if (!WSBMLISTEMPTY(&vpix->scanout_list)) 77 have_handle = (_xa_surface_handle(srf, &handle, &dummy) == XA_ERR_NONE); 78 79 if (xa_surface_redefine(srf, width, height, depth, stype, rgb_format, 80 new_flags, copy_contents) != XA_ERR_NONE) 81 return FALSE; 82 83 if (!WSBMLISTEMPTY(&vpix->scanout_list) && have_handle && 84 _xa_surface_handle(srf, &new_handle, &dummy) == XA_ERR_NONE && 85 new_handle != handle) { 86 LogMessage(X_ERROR, "Changed active scanout surface handle.\n"); 87 } 88 89 return TRUE; 90} 91 92 93/* 94 * Create an xa format from a PICT format. 95 */ 96enum xa_formats 97vmwgfx_xa_format(enum _PictFormatShort format) 98{ 99 uint32_t ptype = PICT_FORMAT_TYPE(format); 100 101 if (ptype >= vmwgfx_stype_map_size || 102 vmwgfx_stype_map[ptype] == 0 || 103 vmwgfx_stype_map[ptype] == xa_type_other) 104 return xa_format_unknown; 105 106 return xa_format(PICT_FORMAT_BPP(format), 107 vmwgfx_stype_map[ptype], 108 PICT_FORMAT_A(format), 109 PICT_FORMAT_R(format), 110 PICT_FORMAT_G(format), 111 PICT_FORMAT_B(format)); 112} 113 114/* 115 * Choose formats and flags for a dri2 surface. 116 */ 117Bool 118vmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth) 119{ 120 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 121 enum xa_formats format; 122 123 if (depth == 0) 124 depth = pixmap->drawable.depth; 125 126 switch(depth) { 127 case 32: 128 format = xa_format_a8r8g8b8; 129 break; 130 case 24: 131 format = xa_format_x8r8g8b8; 132 break; 133 case 16: 134 format = xa_format_r5g6b5; 135 break; 136 case 15: 137 format = xa_format_x1r5g5b5; 138 break; 139 default: 140 return FALSE; 141 } 142 143 vpix->staging_format = format; 144 vpix->staging_remove_flags = 0; 145 vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED; 146 147 return TRUE; 148} 149 150/* 151 * Is composite old format compatible? Only difference is that old format 152 * has more alpha bits? 153 */ 154static inline Bool 155vmwgfx_old_format_compatible(enum xa_formats format, 156 enum xa_formats old_format) 157{ 158 return (format == old_format || 159 (xa_format_type(format) == xa_format_type(old_format) && 160 xa_format_a(format) <= xa_format_a(old_format) && 161 xa_format_r(format) == xa_format_r(old_format) && 162 xa_format_g(format) == xa_format_g(old_format) && 163 xa_format_b(format) == xa_format_b(old_format))); 164} 165 166 167/* 168 * Choose format and flags for a composite dst surface. 169 */ 170Bool 171vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap, 172 enum _PictFormatShort pict_format) 173{ 174 struct vmwgfx_saa *vsaa = 175 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 176 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 177 enum xa_formats format = vmwgfx_xa_format(pict_format); 178 179 /* 180 * Check if we can reuse old hardware format. 181 */ 182 if (vpix->hw) { 183 enum xa_formats old_format = xa_surface_format(vpix->hw); 184 185 if (vmwgfx_old_format_compatible(format, old_format)) 186 format = old_format; 187 } 188 189 if (xa_format_check_supported(vsaa->xat, format, 190 vpix->xa_flags | XA_FLAG_RENDER_TARGET) != 191 XA_ERR_NONE) { 192 return FALSE; 193 } 194 195 vpix->staging_format = format; 196 vpix->staging_remove_flags = 0; 197 vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED; 198 199 return TRUE; 200} 201 202/* 203 * Choose format and flags for a composite src surface. 204 */ 205Bool 206vmwgfx_hw_composite_src_stage(PixmapPtr pixmap, 207 enum _PictFormatShort pict_format) 208{ 209 struct vmwgfx_saa *vsaa = 210 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 211 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 212 enum xa_formats format = vmwgfx_xa_format(pict_format); 213 enum xa_formats swizzle_format = xa_format_unknown; 214 enum xa_surface_type ftype; 215 216 if (format == xa_format_unknown) 217 return FALSE; 218 219 ftype = xa_format_type(format); 220 if (ftype == xa_type_abgr) { 221 222 swizzle_format = xa_format(xa_format_bpp(format), 223 xa_type_argb, 224 xa_format_a(format), 225 xa_format_r(format), 226 xa_format_g(format), 227 xa_format_b(format)); 228 } 229 230 /* 231 * Check if we can reuse old format. 232 */ 233 234 if (vpix->hw) { 235 enum xa_formats old_format = xa_surface_format(vpix->hw); 236 237 if (vmwgfx_old_format_compatible(format, old_format) || 238 (swizzle_format != xa_format_unknown && 239 vmwgfx_old_format_compatible(swizzle_format, old_format))) { 240 format = old_format; 241 goto have_format; 242 } 243 } 244 245 if (swizzle_format != xa_format_unknown && 246 xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) == 247 XA_ERR_NONE) { 248 format = swizzle_format; 249 goto have_format; 250 } 251 252 if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) == 253 XA_ERR_NONE) { 254 goto have_format; 255 } 256 257 return FALSE; 258 have_format: 259 vpix->staging_format = format; 260 vpix->staging_remove_flags = 0; 261 vpix->staging_add_flags = 0; 262 263 return TRUE; 264} 265 266/* 267 * Choose accel format given depth. 268 */ 269static enum xa_formats 270vmwgfx_choose_accel_format(unsigned int depth) 271{ 272 switch(depth) { 273 case 32: 274 return xa_format_a8r8g8b8; 275 case 24: 276 return xa_format_x8r8g8b8; 277 case 16: 278 return xa_format_r5g6b5; 279 case 15: 280 return xa_format_x1r5g5b5; 281 case 8: 282 return xa_format_a8; 283 default: 284 break; 285 } 286 return xa_format_unknown; 287} 288 289 290/* 291 * Determine xa format and flags for an ordinary accel surface. 292 */ 293Bool 294vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth, 295 uint32_t add_flags, uint32_t remove_flags) 296{ 297 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 298 enum xa_formats format = xa_format_unknown; 299 300 if (depth == 0) 301 depth = pixmap->drawable.depth; 302 303 if (vpix->hw) { 304 enum xa_formats old_format = xa_surface_format(vpix->hw); 305 enum xa_surface_type ftype = xa_format_type(old_format); 306 307 if (ftype != xa_type_argb && 308 ftype != xa_type_a) { 309 LogMessage(X_ERROR, 310 "Acceleration fallback due to strange hw format.\n"); 311 return FALSE; 312 } 313 314 if (xa_format_depth(old_format) == depth || 315 (xa_format_depth(old_format) == 32 && 316 depth == 24)) 317 format = old_format; 318 } 319 320 if (format == xa_format_unknown) 321 format = vmwgfx_choose_accel_format(depth); 322 323 if (format == xa_format_unknown) 324 return FALSE; 325 326 vpix->staging_add_flags = add_flags; 327 vpix->staging_remove_flags = remove_flags; 328 vpix->staging_format = format; 329 330 return TRUE; 331} 332 333/* 334 * Create a surface with a format and flags determined by one of 335 * the staging functions. 336 */ 337Bool 338vmwgfx_hw_commit(PixmapPtr pixmap) 339{ 340 struct vmwgfx_saa *vsaa = 341 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 342 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 343 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 344 enum xa_formats format = vpix->staging_format; 345 346 if (vpix->hw) { 347 enum xa_formats old_format = xa_surface_format(vpix->hw); 348 349 if (vpix->staging_format != old_format) { 350 if (xa_format_type(format) != xa_format_type(old_format) || 351 xa_format_r(format) != xa_format_r(old_format) || 352 xa_format_g(format) != xa_format_g(old_format) || 353 xa_format_b(format) != xa_format_b(old_format)) { 354 355 LogMessage(X_INFO, "Killing old hw surface.\n"); 356 357 if (!vmwgfx_hw_kill(vsaa, spix)) 358 return FALSE; 359 } 360 } 361 } 362 363 if (vpix->hw) { 364 uint32_t new_flags; 365 366 new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | 367 vpix->staging_add_flags | XA_FLAG_SHARED; 368 369 if (vpix->staging_format != xa_surface_format(vpix->hw)) 370 LogMessage(X_INFO, "Changing hardware format.\n"); 371 372 if (!vmwgfx_xa_surface_redefine(vpix, 373 vpix->hw, 374 pixmap->drawable.width, 375 pixmap->drawable.height, 376 0, 377 xa_type_other, 378 vpix->staging_format, 379 new_flags, 1) != XA_ERR_NONE) 380 return FALSE; 381 vpix->xa_flags = new_flags; 382 } else if (!vmwgfx_create_hw(vsaa, pixmap, FALSE)) 383 return FALSE; 384 385 return TRUE; 386} 387 388/* 389 * Create an accel surface if there is none, and make sure the region 390 * given by @region is valid. If @region is NULL, the whole surface 391 * will be valid. This is a utility convenience function only. 392 */ 393Bool 394vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth, 395 uint32_t add_flags, uint32_t remove_flags, 396 RegionPtr region) 397{ 398 return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) && 399 vmwgfx_hw_commit(pixmap) && 400 vmwgfx_hw_validate(pixmap, region)); 401} 402 403 404/* 405 * Create a dri2 surface if there is none, 406 * and make sure the whole surfade is valid. 407 * This is a utility convenience function only. 408 */ 409Bool 410vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth) 411{ 412 struct vmwgfx_saa *vsaa = 413 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 414 415 if (!vsaa->is_master) 416 return FALSE; 417 418 return (vmwgfx_hw_dri2_stage(pixmap, depth) && 419 vmwgfx_hw_commit(pixmap) && 420 vmwgfx_hw_validate(pixmap, NULL)); 421} 422