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