vmwgfx_xa_surface.c revision 22f7e8e5
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/* 48 * Create an xa format from a PICT format. 49 */ 50enum xa_formats 51vmwgfx_xa_format(enum _PictFormatShort format) 52{ 53 uint32_t ptype = PICT_FORMAT_TYPE(format); 54 55 if (ptype >= vmwgfx_stype_map_size || 56 vmwgfx_stype_map[ptype] == 0 || 57 vmwgfx_stype_map[ptype] == xa_type_other) 58 return xa_format_unknown; 59 60 return xa_format(PICT_FORMAT_BPP(format), 61 vmwgfx_stype_map[ptype], 62 PICT_FORMAT_A(format), 63 PICT_FORMAT_R(format), 64 PICT_FORMAT_G(format), 65 PICT_FORMAT_B(format)); 66} 67 68/* 69 * Choose formats and flags for a dri2 surface. 70 */ 71static Bool 72vmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth) 73{ 74 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 75 enum xa_formats format; 76 77 if (depth == 0) 78 depth = pixmap->drawable.depth; 79 80 switch(depth) { 81 case 32: 82 format = xa_format_a8r8g8b8; 83 break; 84 case 24: 85 format = xa_format_x8r8g8b8; 86 break; 87 case 16: 88 format = xa_format_r5g6b5; 89 break; 90 case 15: 91 format = xa_format_x1r5g5b5; 92 break; 93 default: 94 return FALSE; 95 } 96 97 vpix->staging_format = format; 98 vpix->staging_remove_flags = 0; 99 vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED; 100 101 return TRUE; 102} 103 104/* 105 * Is composite old format compatible? Only difference is that old format 106 * has more alpha bits? 107 */ 108static inline Bool 109vmwgfx_old_format_compatible(enum xa_formats format, 110 enum xa_formats old_format) 111{ 112 return (format == old_format || 113 (xa_format_type(format) == xa_format_type(old_format) && 114 xa_format_a(format) <= xa_format_a(old_format) && 115 xa_format_r(format) == xa_format_r(old_format) && 116 xa_format_g(format) == xa_format_g(old_format) && 117 xa_format_b(format) == xa_format_b(old_format))); 118} 119 120 121/* 122 * Choose format and flags for a composite dst surface. 123 */ 124Bool 125vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap, 126 enum _PictFormatShort pict_format) 127{ 128 struct vmwgfx_saa *vsaa = 129 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 130 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 131 enum xa_formats format = vmwgfx_xa_format(pict_format); 132 133 /* 134 * Check if we can reuse old hardware format. 135 */ 136 if (vpix->hw) { 137 enum xa_formats old_format = xa_surface_format(vpix->hw); 138 139 if (vmwgfx_old_format_compatible(format, old_format)) 140 format = old_format; 141 } 142 143 if (xa_format_check_supported(vsaa->xat, format, 144 vpix->xa_flags | XA_FLAG_RENDER_TARGET) != 145 XA_ERR_NONE) { 146 return FALSE; 147 } 148 149 vpix->staging_format = format; 150 vpix->staging_remove_flags = 0; 151 vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED; 152 153 return TRUE; 154} 155 156/* 157 * Choose format and flags for a composite src surface. 158 */ 159Bool 160vmwgfx_hw_composite_src_stage(PixmapPtr pixmap, 161 enum _PictFormatShort pict_format) 162{ 163 struct vmwgfx_saa *vsaa = 164 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 165 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 166 enum xa_formats format = vmwgfx_xa_format(pict_format); 167 enum xa_formats swizzle_format = xa_format_unknown; 168 enum xa_surface_type ftype; 169 170 if (format == xa_format_unknown) 171 return FALSE; 172 173 ftype = xa_format_type(format); 174 if (ftype == xa_type_abgr) { 175 176 swizzle_format = xa_format(xa_format_bpp(format), 177 xa_type_argb, 178 xa_format_a(format), 179 xa_format_r(format), 180 xa_format_g(format), 181 xa_format_b(format)); 182 } 183 184 /* 185 * Check if we can reuse old format. 186 */ 187 188 if (vpix->hw) { 189 enum xa_formats old_format = xa_surface_format(vpix->hw); 190 191 if (vmwgfx_old_format_compatible(format, old_format) || 192 (swizzle_format != xa_format_unknown && 193 vmwgfx_old_format_compatible(swizzle_format, old_format))) { 194 format = old_format; 195 goto have_format; 196 } 197 } 198 199 if (swizzle_format != xa_format_unknown && 200 xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) == 201 XA_ERR_NONE) { 202 format = swizzle_format; 203 goto have_format; 204 } 205 206 if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) == 207 XA_ERR_NONE) { 208 goto have_format; 209 } 210 211 return FALSE; 212 have_format: 213 vpix->staging_format = format; 214 vpix->staging_remove_flags = 0; 215 vpix->staging_add_flags = 0; 216 217 return TRUE; 218} 219 220/* 221 * Choose accel format given depth. 222 */ 223static enum xa_formats 224vmwgfx_choose_accel_format(unsigned int depth) 225{ 226 switch(depth) { 227 case 32: 228 return xa_format_a8r8g8b8; 229 case 24: 230 return xa_format_x8r8g8b8; 231 case 16: 232 return xa_format_r5g6b5; 233 case 15: 234 return xa_format_x1r5g5b5; 235 case 8: 236 return xa_format_a8; 237 default: 238 break; 239 } 240 return xa_format_unknown; 241} 242 243 244/* 245 * Determine xa format and flags for an ordinary accel surface. 246 */ 247Bool 248vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth, 249 uint32_t add_flags, uint32_t remove_flags) 250{ 251 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 252 enum xa_formats format = xa_format_unknown; 253 254 if (depth == 0) 255 depth = pixmap->drawable.depth; 256 257 if (vpix->hw) { 258 enum xa_formats old_format = xa_surface_format(vpix->hw); 259 enum xa_surface_type ftype = xa_format_type(old_format); 260 261 if (ftype != xa_type_argb && 262 ftype != xa_type_a) { 263 LogMessage(X_ERROR, 264 "Acceleration fallback due to strange hw format.\n"); 265 return FALSE; 266 } 267 268 if (xa_format_depth(old_format) == depth || 269 (xa_format_depth(old_format) == 32 && 270 depth == 24)) 271 format = old_format; 272 } 273 274 if (format == xa_format_unknown) 275 format = vmwgfx_choose_accel_format(depth); 276 277 if (format == xa_format_unknown) 278 return FALSE; 279 280 vpix->staging_add_flags = add_flags; 281 vpix->staging_remove_flags = remove_flags; 282 vpix->staging_format = format; 283 284 return TRUE; 285} 286 287/* 288 * Create a surface with a format and flags determined by one of 289 * the staging functions. 290 */ 291Bool 292vmwgfx_hw_commit(PixmapPtr pixmap) 293{ 294 struct vmwgfx_saa *vsaa = 295 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 296 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 297 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 298 enum xa_formats format = vpix->staging_format; 299 300 if (vpix->hw) { 301 enum xa_formats old_format = xa_surface_format(vpix->hw); 302 303 if (vpix->staging_format != old_format) { 304 if (xa_format_type(format) != xa_format_type(old_format) || 305 xa_format_r(format) != xa_format_r(old_format) || 306 xa_format_g(format) != xa_format_g(old_format) || 307 xa_format_b(format) != xa_format_b(old_format)) { 308 309 LogMessage(X_INFO, "Killing old hw surface.\n"); 310 311 if (!vmwgfx_hw_kill(vsaa, spix)) 312 return FALSE; 313 } 314 } 315 } 316 317 if (vpix->hw) { 318 uint32_t new_flags; 319 320 new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | 321 vpix->staging_add_flags | XA_FLAG_SHARED; 322 323 if (vpix->staging_format != xa_surface_format(vpix->hw)) 324 LogMessage(X_INFO, "Changing hardware format.\n"); 325 326 if (xa_surface_redefine(vpix->hw, 327 pixmap->drawable.width, 328 pixmap->drawable.height, 329 0, 330 xa_type_other, 331 vpix->staging_format, 332 new_flags, 1) != XA_ERR_NONE) 333 return FALSE; 334 vpix->xa_flags = new_flags; 335 } else if (!vmwgfx_create_hw(vsaa, pixmap)) 336 return FALSE; 337 338 return TRUE; 339} 340 341/* 342 * Create an accel surface if there is none, and make sure the region 343 * given by @region is valid. If @region is NULL, the whole surface 344 * will be valid. This is a utility convenience function only. 345 */ 346Bool 347vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth, 348 uint32_t add_flags, uint32_t remove_flags, 349 RegionPtr region) 350{ 351 return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) && 352 vmwgfx_hw_commit(pixmap) && 353 vmwgfx_hw_validate(pixmap, region)); 354} 355 356 357/* 358 * Create a dri2 surface if there is none, 359 * and make sure the whole surfade is valid. 360 * This is a utility convenience function only. 361 */ 362Bool 363vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth) 364{ 365 struct vmwgfx_saa *vsaa = 366 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 367 368 if (!vsaa->is_master) 369 return FALSE; 370 371 return (vmwgfx_hw_dri2_stage(pixmap, depth) && 372 vmwgfx_hw_commit(pixmap) && 373 vmwgfx_hw_validate(pixmap, NULL)); 374} 375