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