1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright (C) 2010 LunarG Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Chia-I Wu <olv (at) lunarg.com> 27 */ 28 29 #include "xm_api.h" 30 #include "xm_st.h" 31 32 #include "util/u_inlines.h" 33 #include "util/u_atomic.h" 34 35 struct xmesa_st_framebuffer { 36 XMesaDisplay display; 37 XMesaBuffer buffer; 38 struct pipe_screen *screen; 39 40 struct st_visual stvis; 41 enum pipe_texture_target target; 42 43 unsigned texture_width, texture_height, texture_mask; 44 struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; 45 46 struct pipe_resource *display_resource; 47 }; 48 49 static INLINE struct xmesa_st_framebuffer * 50 xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi) 51 { 52 return (struct xmesa_st_framebuffer *) stfbi->st_manager_private; 53 } 54 55 /** 56 * Display an attachment to the xlib_drawable of the framebuffer. 57 */ 58 static boolean 59 xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi, 60 enum st_attachment_type statt) 61 { 62 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 63 struct pipe_resource *ptex = xstfb->textures[statt]; 64 struct pipe_resource *pres; 65 66 if (!ptex) 67 return TRUE; 68 69 pres = xstfb->display_resource; 70 /* (re)allocate the surface for the texture to be displayed */ 71 if (!pres || pres != ptex) { 72 pipe_resource_reference(&xstfb->display_resource, ptex); 73 pres = xstfb->display_resource; 74 } 75 76 xstfb->screen->flush_frontbuffer(xstfb->screen, pres, 0, 0, &xstfb->buffer->ws); 77 78 return TRUE; 79 } 80 81 /** 82 * Copy the contents between the attachments. 83 */ 84 static void 85 xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi, 86 enum st_attachment_type src_statt, 87 enum st_attachment_type dst_statt, 88 unsigned x, unsigned y, 89 unsigned width, unsigned height) 90 { 91 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 92 struct pipe_resource *src_ptex = xstfb->textures[src_statt]; 93 struct pipe_resource *dst_ptex = xstfb->textures[dst_statt]; 94 struct pipe_box src_box; 95 struct pipe_context *pipe; 96 97 if (!src_ptex || !dst_ptex) 98 return; 99 100 pipe = xmesa_get_context(stfbi); 101 102 u_box_2d(x, y, width, height, &src_box); 103 104 if (src_ptex && dst_ptex) 105 pipe->resource_copy_region(pipe, dst_ptex, 0, x, y, 0, 106 src_ptex, 0, &src_box); 107 } 108 109 /** 110 * Remove outdated textures and create the requested ones. 111 * This is a helper used during framebuffer validation. 112 */ 113 boolean 114 xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, 115 unsigned width, unsigned height, 116 unsigned mask) 117 { 118 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 119 struct pipe_resource templ; 120 enum st_attachment_type i; 121 122 /* remove outdated textures */ 123 if (xstfb->texture_width != width || xstfb->texture_height != height) { 124 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 125 pipe_resource_reference(&xstfb->textures[i], NULL); 126 } 127 128 memset(&templ, 0, sizeof(templ)); 129 templ.target = xstfb->target; 130 templ.width0 = width; 131 templ.height0 = height; 132 templ.depth0 = 1; 133 templ.array_size = 1; 134 templ.last_level = 0; 135 136 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 137 enum pipe_format format; 138 unsigned bind; 139 140 /* the texture already exists or not requested */ 141 if (xstfb->textures[i] || !(mask & (1 << i))) { 142 /* remember the texture */ 143 if (xstfb->textures[i]) 144 mask |= (1 << i); 145 continue; 146 } 147 148 switch (i) { 149 case ST_ATTACHMENT_FRONT_LEFT: 150 case ST_ATTACHMENT_BACK_LEFT: 151 case ST_ATTACHMENT_FRONT_RIGHT: 152 case ST_ATTACHMENT_BACK_RIGHT: 153 format = xstfb->stvis.color_format; 154 bind = PIPE_BIND_DISPLAY_TARGET | 155 PIPE_BIND_RENDER_TARGET; 156 break; 157 case ST_ATTACHMENT_DEPTH_STENCIL: 158 format = xstfb->stvis.depth_stencil_format; 159 bind = PIPE_BIND_DEPTH_STENCIL; 160 break; 161 default: 162 format = PIPE_FORMAT_NONE; 163 break; 164 } 165 166 if (format != PIPE_FORMAT_NONE) { 167 templ.format = format; 168 templ.bind = bind; 169 170 xstfb->textures[i] = 171 xstfb->screen->resource_create(xstfb->screen, &templ); 172 if (!xstfb->textures[i]) 173 return FALSE; 174 } 175 } 176 177 xstfb->texture_width = width; 178 xstfb->texture_height = height; 179 xstfb->texture_mask = mask; 180 181 return TRUE; 182 } 183 184 185 /** 186 * Check that a framebuffer's attachments match the window's size. 187 * 188 * Called via st_framebuffer_iface::validate() 189 * 190 * \param statts array of framebuffer attachments 191 * \param count number of framebuffer attachments in statts[] 192 * \param out returns resources for each of the attachments 193 */ 194 static boolean 195 xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, 196 const enum st_attachment_type *statts, 197 unsigned count, 198 struct pipe_resource **out) 199 { 200 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 201 unsigned statt_mask, new_mask, i; 202 boolean resized; 203 boolean ret; 204 205 /* build mask of ST_ATTACHMENT bits */ 206 statt_mask = 0x0; 207 for (i = 0; i < count; i++) 208 statt_mask |= 1 << statts[i]; 209 210 /* record newly allocated textures */ 211 new_mask = statt_mask & ~xstfb->texture_mask; 212 213 /* If xmesa_strict_invalidate is not set, we will not yet have 214 * called XGetGeometry(). Do so here: 215 */ 216 if (!xmesa_strict_invalidate) 217 xmesa_check_buffer_size(xstfb->buffer); 218 219 resized = (xstfb->buffer->width != xstfb->texture_width || 220 xstfb->buffer->height != xstfb->texture_height); 221 222 /* revalidate textures */ 223 if (resized || new_mask) { 224 ret = xmesa_st_framebuffer_validate_textures(stfbi, 225 xstfb->buffer->width, xstfb->buffer->height, statt_mask); 226 if (!ret) 227 return ret; 228 229 if (!resized) { 230 enum st_attachment_type back, front; 231 232 back = ST_ATTACHMENT_BACK_LEFT; 233 front = ST_ATTACHMENT_FRONT_LEFT; 234 /* copy the contents if front is newly allocated and back is not */ 235 if ((statt_mask & (1 << back)) && 236 (new_mask & (1 << front)) && 237 !(new_mask & (1 << back))) { 238 xmesa_st_framebuffer_copy_textures(stfbi, back, front, 239 0, 0, xstfb->texture_width, xstfb->texture_height); 240 } 241 } 242 } 243 244 for (i = 0; i < count; i++) { 245 out[i] = NULL; 246 pipe_resource_reference(&out[i], xstfb->textures[statts[i]]); 247 } 248 249 return TRUE; 250 } 251 252 /** 253 * Called via st_framebuffer_iface::flush_front() 254 */ 255 static boolean 256 xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, 257 enum st_attachment_type statt) 258 { 259 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 260 boolean ret; 261 262 ret = xmesa_st_framebuffer_display(stfbi, statt); 263 264 if (ret && xmesa_strict_invalidate) 265 xmesa_check_buffer_size(xstfb->buffer); 266 267 return ret; 268 } 269 270 struct st_framebuffer_iface * 271 xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) 272 { 273 struct st_framebuffer_iface *stfbi; 274 struct xmesa_st_framebuffer *xstfb; 275 276 assert(xmdpy->display == b->xm_visual->display); 277 278 stfbi = CALLOC_STRUCT(st_framebuffer_iface); 279 xstfb = CALLOC_STRUCT(xmesa_st_framebuffer); 280 if (!stfbi || !xstfb) { 281 if (stfbi) 282 FREE(stfbi); 283 if (xstfb) 284 FREE(xstfb); 285 return NULL; 286 } 287 288 xstfb->display = xmdpy; 289 xstfb->buffer = b; 290 xstfb->screen = xmdpy->screen; 291 xstfb->stvis = b->xm_visual->stvis; 292 if(xstfb->screen->get_param(xstfb->screen, PIPE_CAP_NPOT_TEXTURES)) 293 xstfb->target = PIPE_TEXTURE_2D; 294 else 295 xstfb->target = PIPE_TEXTURE_RECT; 296 297 stfbi->visual = &xstfb->stvis; 298 stfbi->flush_front = xmesa_st_framebuffer_flush_front; 299 stfbi->validate = xmesa_st_framebuffer_validate; 300 p_atomic_set(&stfbi->stamp, 1); 301 stfbi->st_manager_private = (void *) xstfb; 302 303 return stfbi; 304 } 305 306 void 307 xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi) 308 { 309 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 310 int i; 311 312 pipe_resource_reference(&xstfb->display_resource, NULL); 313 314 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 315 pipe_resource_reference(&xstfb->textures[i], NULL); 316 317 FREE(xstfb); 318 FREE(stfbi); 319 } 320 321 void 322 xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi) 323 { 324 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 325 boolean ret; 326 327 ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT); 328 if (ret) { 329 struct pipe_resource **front, **back, *tmp; 330 331 front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT]; 332 back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT]; 333 /* swap textures only if the front texture has been allocated */ 334 if (*front) { 335 tmp = *front; 336 *front = *back; 337 *back = tmp; 338 339 /* the current context should validate the buffer after swapping */ 340 if (!xmesa_strict_invalidate) 341 xmesa_notify_invalid_buffer(xstfb->buffer); 342 } 343 344 if (xmesa_strict_invalidate) 345 xmesa_check_buffer_size(xstfb->buffer); 346 } 347 } 348 349 void 350 xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi, 351 enum st_attachment_type src, 352 enum st_attachment_type dst, 353 int x, int y, int w, int h) 354 { 355 xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h); 356 if (dst == ST_ATTACHMENT_FRONT_LEFT) 357 xmesa_st_framebuffer_display(stfbi, dst); 358 } 359 360 struct pipe_resource* 361 xmesa_get_attachment(struct st_framebuffer_iface *stfbi, 362 enum st_attachment_type st_attachment) 363 { 364 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 365 struct pipe_resource* res; 366 367 res = xstfb->textures[st_attachment]; 368 return res; 369 } 370 371 struct pipe_context* 372 xmesa_get_context(struct st_framebuffer_iface* stfbi) 373 { 374 struct pipe_context *pipe; 375 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 376 377 pipe = xstfb->display->pipe; 378 if (!pipe) { 379 pipe = xstfb->screen->context_create(xstfb->screen, NULL); 380 if (!pipe) 381 return NULL; 382 xstfb->display->pipe = pipe; 383 } 384 return pipe; 385 } 386 387