xm_st.c revision 4c7001462607e6e99e474d6271dd481d3f8f201c
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@lunarg.com> 27 */ 28 29#include "xm_api.h" 30#include "xm_st.h" 31 32#include "util/u_inlines.h" 33 34struct xmesa_st_framebuffer { 35 XMesaDisplay display; 36 XMesaBuffer buffer; 37 struct pipe_screen *screen; 38 39 struct st_visual stvis; 40 enum pipe_texture_target target; 41 42 unsigned texture_width, texture_height, texture_mask; 43 struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; 44 45 struct pipe_resource *display_resource; 46}; 47 48static INLINE struct xmesa_st_framebuffer * 49xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi) 50{ 51 return (struct xmesa_st_framebuffer *) stfbi->st_manager_private; 52} 53 54/** 55 * Display an attachment to the xlib_drawable of the framebuffer. 56 */ 57static boolean 58xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi, 59 enum st_attachment_type statt) 60{ 61 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 62 struct pipe_resource *ptex = xstfb->textures[statt]; 63 struct pipe_resource *pres; 64 65 if (!ptex) 66 return TRUE; 67 68 pres = xstfb->display_resource; 69 /* (re)allocate the surface for the texture to be displayed */ 70 if (!pres || pres != ptex) { 71 pipe_resource_reference(&xstfb->display_resource, ptex); 72 pres = xstfb->display_resource; 73 } 74 75 xstfb->screen->flush_frontbuffer(xstfb->screen, pres, 0, 0, &xstfb->buffer->ws); 76 77 return TRUE; 78} 79 80/** 81 * Copy the contents between the attachments. 82 */ 83static void 84xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi, 85 enum st_attachment_type src_statt, 86 enum st_attachment_type dst_statt, 87 unsigned x, unsigned y, 88 unsigned width, unsigned height) 89{ 90 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 91 struct pipe_resource *src_ptex = xstfb->textures[src_statt]; 92 struct pipe_resource *dst_ptex = xstfb->textures[dst_statt]; 93 struct pipe_box src_box; 94 struct pipe_context *pipe; 95 96 if (!src_ptex || !dst_ptex) 97 return; 98 99 pipe = xstfb->display->pipe; 100 if (!pipe) { 101 pipe = xstfb->screen->context_create(xstfb->screen, NULL); 102 if (!pipe) 103 return; 104 xstfb->display->pipe = pipe; 105 } 106 107 u_box_2d(x, y, width, height, &src_box); 108 109 if (src_ptex && dst_ptex) 110 pipe->resource_copy_region(pipe, dst_ptex, 0, x, y, 0, 111 src_ptex, 0, &src_box); 112} 113 114/** 115 * Remove outdated textures and create the requested ones. 116 * This is a helper used during framebuffer validation. 117 */ 118static boolean 119xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, 120 unsigned width, unsigned height, 121 unsigned mask) 122{ 123 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 124 struct pipe_resource templ; 125 enum st_attachment_type i; 126 127 /* remove outdated textures */ 128 if (xstfb->texture_width != width || xstfb->texture_height != height) { 129 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 130 pipe_resource_reference(&xstfb->textures[i], NULL); 131 } 132 133 memset(&templ, 0, sizeof(templ)); 134 templ.target = xstfb->target; 135 templ.width0 = width; 136 templ.height0 = height; 137 templ.depth0 = 1; 138 templ.array_size = 1; 139 templ.last_level = 0; 140 141 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 142 enum pipe_format format; 143 unsigned bind; 144 145 /* the texture already exists or not requested */ 146 if (xstfb->textures[i] || !(mask & (1 << i))) { 147 /* remember the texture */ 148 if (xstfb->textures[i]) 149 mask |= (1 << i); 150 continue; 151 } 152 153 switch (i) { 154 case ST_ATTACHMENT_FRONT_LEFT: 155 case ST_ATTACHMENT_BACK_LEFT: 156 case ST_ATTACHMENT_FRONT_RIGHT: 157 case ST_ATTACHMENT_BACK_RIGHT: 158 format = xstfb->stvis.color_format; 159 bind = PIPE_BIND_DISPLAY_TARGET | 160 PIPE_BIND_RENDER_TARGET; 161 break; 162 case ST_ATTACHMENT_DEPTH_STENCIL: 163 format = xstfb->stvis.depth_stencil_format; 164 bind = PIPE_BIND_DEPTH_STENCIL; 165 break; 166 default: 167 format = PIPE_FORMAT_NONE; 168 break; 169 } 170 171 if (format != PIPE_FORMAT_NONE) { 172 templ.format = format; 173 templ.bind = bind; 174 175 xstfb->textures[i] = 176 xstfb->screen->resource_create(xstfb->screen, &templ); 177 if (!xstfb->textures[i]) 178 return FALSE; 179 } 180 } 181 182 xstfb->texture_width = width; 183 xstfb->texture_height = height; 184 xstfb->texture_mask = mask; 185 186 return TRUE; 187} 188 189 190/** 191 * Check that a framebuffer's attachments match the window's size. 192 * 193 * Called via st_framebuffer_iface::validate() 194 * 195 * \param statts array of framebuffer attachments 196 * \param count number of framebuffer attachments in statts[] 197 * \param out returns resources for each of the attachments 198 */ 199static boolean 200xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, 201 const enum st_attachment_type *statts, 202 unsigned count, 203 struct pipe_resource **out) 204{ 205 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 206 unsigned statt_mask, new_mask, i; 207 boolean resized; 208 boolean ret; 209 210 /* build mask of ST_ATTACHMENT bits */ 211 statt_mask = 0x0; 212 for (i = 0; i < count; i++) 213 statt_mask |= 1 << statts[i]; 214 215 /* record newly allocated textures */ 216 new_mask = statt_mask & ~xstfb->texture_mask; 217 218 /* If xmesa_strict_invalidate is not set, we will not yet have 219 * called XGetGeometry(). Do so here: 220 */ 221 if (!xmesa_strict_invalidate) 222 xmesa_check_buffer_size(xstfb->buffer); 223 224 resized = (xstfb->buffer->width != xstfb->texture_width || 225 xstfb->buffer->height != xstfb->texture_height); 226 227 /* revalidate textures */ 228 if (resized || new_mask) { 229 ret = xmesa_st_framebuffer_validate_textures(stfbi, 230 xstfb->buffer->width, xstfb->buffer->height, statt_mask); 231 if (!ret) 232 return ret; 233 234 if (!resized) { 235 enum st_attachment_type back, front; 236 237 back = ST_ATTACHMENT_BACK_LEFT; 238 front = ST_ATTACHMENT_FRONT_LEFT; 239 /* copy the contents if front is newly allocated and back is not */ 240 if ((statt_mask & (1 << back)) && 241 (new_mask & (1 << front)) && 242 !(new_mask & (1 << back))) { 243 xmesa_st_framebuffer_copy_textures(stfbi, back, front, 244 0, 0, xstfb->texture_width, xstfb->texture_height); 245 } 246 } 247 } 248 249 for (i = 0; i < count; i++) { 250 out[i] = NULL; 251 pipe_resource_reference(&out[i], xstfb->textures[statts[i]]); 252 } 253 254 return TRUE; 255} 256 257/** 258 * Called via st_framebuffer_iface::flush_front() 259 */ 260static boolean 261xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, 262 enum st_attachment_type statt) 263{ 264 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 265 boolean ret; 266 267 ret = xmesa_st_framebuffer_display(stfbi, statt); 268 269 if (ret && xmesa_strict_invalidate) 270 xmesa_check_buffer_size(xstfb->buffer); 271 272 return ret; 273} 274 275struct st_framebuffer_iface * 276xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) 277{ 278 struct st_framebuffer_iface *stfbi; 279 struct xmesa_st_framebuffer *xstfb; 280 281 assert(xmdpy->display == b->xm_visual->display); 282 283 stfbi = CALLOC_STRUCT(st_framebuffer_iface); 284 xstfb = CALLOC_STRUCT(xmesa_st_framebuffer); 285 if (!stfbi || !xstfb) { 286 if (stfbi) 287 FREE(stfbi); 288 if (xstfb) 289 FREE(xstfb); 290 return NULL; 291 } 292 293 xstfb->display = xmdpy; 294 xstfb->buffer = b; 295 xstfb->screen = xmdpy->screen; 296 xstfb->stvis = b->xm_visual->stvis; 297 if(xstfb->screen->get_param(xstfb->screen, PIPE_CAP_NPOT_TEXTURES)) 298 xstfb->target = PIPE_TEXTURE_2D; 299 else 300 xstfb->target = PIPE_TEXTURE_RECT; 301 302 stfbi->visual = &xstfb->stvis; 303 stfbi->flush_front = xmesa_st_framebuffer_flush_front; 304 stfbi->validate = xmesa_st_framebuffer_validate; 305 stfbi->st_manager_private = (void *) xstfb; 306 307 return stfbi; 308} 309 310void 311xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi) 312{ 313 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 314 int i; 315 316 pipe_resource_reference(&xstfb->display_resource, NULL); 317 318 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 319 pipe_resource_reference(&xstfb->textures[i], NULL); 320 321 FREE(xstfb); 322 FREE(stfbi); 323} 324 325void 326xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi) 327{ 328 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 329 boolean ret; 330 331 ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT); 332 if (ret) { 333 struct pipe_resource **front, **back, *tmp; 334 335 front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT]; 336 back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT]; 337 /* swap textures only if the front texture has been allocated */ 338 if (*front) { 339 tmp = *front; 340 *front = *back; 341 *back = tmp; 342 343 /* the current context should validate the buffer after swapping */ 344 if (!xmesa_strict_invalidate) 345 xmesa_notify_invalid_buffer(xstfb->buffer); 346 } 347 348 if (xmesa_strict_invalidate) 349 xmesa_check_buffer_size(xstfb->buffer); 350 } 351} 352 353void 354xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi, 355 enum st_attachment_type src, 356 enum st_attachment_type dst, 357 int x, int y, int w, int h) 358{ 359 xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h); 360 if (dst == ST_ATTACHMENT_FRONT_LEFT) 361 xmesa_st_framebuffer_display(stfbi, dst); 362} 363