xm_st.c revision 23e9a25e1ff01d9f3ef5cc99f59e0fda0ac2d421
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 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Chia-I Wu <olv@lunarg.com> 26 */ 27 28#include "util/u_memory.h" 29#include "util/u_inlines.h" 30 31#include "xm_api.h" 32#include "xm_st.h" 33 34struct xmesa_st_framebuffer { 35 XMesaDisplay display; 36 XMesaBuffer buffer; 37 struct pipe_screen *screen; 38 39 struct st_visual stvis; 40 41 unsigned texture_width, texture_height, texture_mask; 42 struct pipe_texture *textures[ST_ATTACHMENT_COUNT]; 43 44 struct pipe_surface *display_surface; 45}; 46 47static INLINE struct xmesa_st_framebuffer * 48xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi) 49{ 50 return (struct xmesa_st_framebuffer *) stfbi->st_manager_private; 51} 52 53/** 54 * Display an attachment to the xlib_drawable of the framebuffer. 55 */ 56static boolean 57xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi, 58 enum st_attachment_type statt) 59{ 60 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 61 struct pipe_texture *ptex = xstfb->textures[statt]; 62 struct pipe_surface *psurf; 63 64 if (!ptex) 65 return TRUE; 66 67 psurf = xstfb->display_surface; 68 /* (re)allocate the surface for the texture to be displayed */ 69 if (!psurf || psurf->texture != ptex) { 70 pipe_surface_reference(&xstfb->display_surface, NULL); 71 72 psurf = xstfb->screen->get_tex_surface(xstfb->screen, 73 ptex, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ); 74 if (!psurf) 75 return FALSE; 76 77 xstfb->display_surface = psurf; 78 } 79 80 xstfb->screen->flush_frontbuffer(xstfb->screen, psurf, &xstfb->buffer->ws); 81 82 return TRUE; 83} 84 85/** 86 * Copy the contents between the attachments. 87 */ 88static void 89xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi, 90 enum st_attachment_type src_statt, 91 enum st_attachment_type dst_statt, 92 unsigned x, unsigned y, 93 unsigned width, unsigned height) 94{ 95 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 96 struct pipe_texture *src_ptex = xstfb->textures[src_statt]; 97 struct pipe_texture *dst_ptex = xstfb->textures[dst_statt]; 98 struct pipe_surface *src, *dst; 99 struct pipe_context *pipe; 100 101 if (!src_ptex || !dst_ptex) 102 return; 103 104 pipe = xstfb->display->pipe; 105 if (!pipe) { 106 pipe = xstfb->screen->context_create(xstfb->screen, NULL); 107 if (!pipe) 108 return; 109 xstfb->display->pipe = pipe; 110 } 111 112 src = xstfb->screen->get_tex_surface(xstfb->screen, 113 src_ptex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ); 114 dst = xstfb->screen->get_tex_surface(xstfb->screen, 115 dst_ptex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE); 116 117 if (src && dst) 118 pipe->surface_copy(pipe, dst, x, y, src, x, y, width, height); 119 120 pipe_surface_reference(&src, NULL); 121 pipe_surface_reference(&dst, NULL); 122} 123 124/** 125 * Remove outdated textures and create the requested ones. 126 */ 127static void 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_texture templ; 134 unsigned 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_texture_reference(&xstfb->textures[i], NULL); 140 } 141 142 memset(&templ, 0, sizeof(templ)); 143 templ.target = PIPE_TEXTURE_2D; 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 tex_usage; 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 tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET | 168 PIPE_TEXTURE_USAGE_RENDER_TARGET; 169 break; 170 case ST_ATTACHMENT_DEPTH_STENCIL: 171 format = xstfb->stvis.depth_stencil_format; 172 tex_usage = PIPE_TEXTURE_USAGE_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.tex_usage = tex_usage; 182 183 xstfb->textures[i] = 184 xstfb->screen->texture_create(xstfb->screen, &templ); 185 } 186 } 187 188 xstfb->texture_width = width; 189 xstfb->texture_height = height; 190 xstfb->texture_mask = mask; 191} 192 193static boolean 194xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, 195 const enum st_attachment_type *statts, 196 unsigned count, 197 struct pipe_texture **out) 198{ 199 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 200 unsigned statt_mask, new_mask, i; 201 boolean resized; 202 203 statt_mask = 0x0; 204 for (i = 0; i < count; i++) 205 statt_mask |= 1 << statts[i]; 206 /* record newly allocated textures */ 207 new_mask = statt_mask & ~xstfb->texture_mask; 208 209 resized = (xstfb->buffer->width != xstfb->texture_width || 210 xstfb->buffer->height != xstfb->texture_height); 211 212 /* revalidate textures */ 213 if (resized || new_mask) { 214 xmesa_st_framebuffer_validate_textures(stfbi, 215 xstfb->buffer->width, xstfb->buffer->height, statt_mask); 216 217 if (!resized) { 218 enum st_attachment_type back, front; 219 220 back = ST_ATTACHMENT_BACK_LEFT; 221 front = ST_ATTACHMENT_FRONT_LEFT; 222 /* copy the contents if front is newly allocated and back is not */ 223 if ((statt_mask & (1 << back)) && 224 (new_mask & (1 << front)) && 225 !(new_mask & (1 << back))) { 226 xmesa_st_framebuffer_copy_textures(stfbi, back, front, 227 0, 0, xstfb->texture_width, xstfb->texture_height); 228 } 229 } 230 } 231 232 for (i = 0; i < count; i++) { 233 out[i] = NULL; 234 pipe_texture_reference(&out[i], xstfb->textures[statts[i]]); 235 } 236 237 return TRUE; 238} 239 240static boolean 241xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, 242 enum st_attachment_type statt) 243{ 244 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 245 boolean ret; 246 247 ret = xmesa_st_framebuffer_display(stfbi, statt); 248 if (ret) 249 xmesa_check_buffer_size(xstfb->buffer); 250 251 return ret; 252} 253 254struct st_framebuffer_iface * 255xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) 256{ 257 struct st_framebuffer_iface *stfbi; 258 struct xmesa_st_framebuffer *xstfb; 259 260 assert(xmdpy->display == b->xm_visual->display); 261 262 stfbi = CALLOC_STRUCT(st_framebuffer_iface); 263 xstfb = CALLOC_STRUCT(xmesa_st_framebuffer); 264 if (!stfbi || !xstfb) { 265 if (stfbi) 266 FREE(stfbi); 267 if (xstfb) 268 FREE(xstfb); 269 return NULL; 270 } 271 272 xstfb->display = xmdpy; 273 xstfb->buffer = b; 274 xstfb->screen = xmdpy->screen; 275 xstfb->stvis = b->xm_visual->stvis; 276 277 stfbi->visual = &xstfb->stvis; 278 stfbi->flush_front = xmesa_st_framebuffer_flush_front; 279 stfbi->validate = xmesa_st_framebuffer_validate; 280 stfbi->st_manager_private = (void *) xstfb; 281 282 return stfbi; 283} 284 285void 286xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi) 287{ 288 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 289 int i; 290 291 pipe_surface_reference(&xstfb->display_surface, NULL); 292 293 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 294 pipe_texture_reference(&xstfb->textures[i], NULL); 295 296 FREE(xstfb); 297 FREE(stfbi); 298} 299 300void 301xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi) 302{ 303 struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); 304 boolean ret; 305 306 ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT); 307 if (ret) { 308 struct pipe_texture **front, **back, *tmp; 309 310 front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT]; 311 back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT]; 312 /* swap textures only if the front texture has been allocated */ 313 if (*front) { 314 tmp = *front; 315 *front = *back; 316 *back = tmp; 317 } 318 319 xmesa_check_buffer_size(xstfb->buffer); 320 } 321} 322 323void 324xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi, 325 enum st_attachment_type src, 326 enum st_attachment_type dst, 327 int x, int y, int w, int h) 328{ 329 xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h); 330 if (dst == ST_ATTACHMENT_FRONT_LEFT) 331 xmesa_st_framebuffer_display(stfbi, dst); 332} 333