glamor_fbo.c revision 1b5d61b8
1/* 2 * Copyright © 2009 Intel Corporation 3 * Copyright © 1998 Keith Packard 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * Authors: 25 * Zhigang Gong <zhigang.gong@gmail.com> 26 * 27 */ 28 29#include <stdlib.h> 30 31#include "glamor_priv.h" 32 33void 34glamor_destroy_fbo(glamor_screen_private *glamor_priv, 35 glamor_pixmap_fbo *fbo) 36{ 37 glamor_make_current(glamor_priv); 38 39 if (fbo->fb) 40 glDeleteFramebuffers(1, &fbo->fb); 41 if (fbo->tex) 42 glDeleteTextures(1, &fbo->tex); 43 44 free(fbo); 45} 46 47static int 48glamor_pixmap_ensure_fb(glamor_screen_private *glamor_priv, 49 glamor_pixmap_fbo *fbo) 50{ 51 int status, err = 0; 52 53 glamor_make_current(glamor_priv); 54 55 if (fbo->fb == 0) 56 glGenFramebuffers(1, &fbo->fb); 57 assert(fbo->tex != 0); 58 glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); 59 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 60 GL_TEXTURE_2D, fbo->tex, 0); 61 status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 62 if (status != GL_FRAMEBUFFER_COMPLETE) { 63 const char *str; 64 65 switch (status) { 66 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 67 str = "incomplete attachment"; 68 break; 69 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 70 str = "incomplete/missing attachment"; 71 break; 72 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: 73 str = "incomplete draw buffer"; 74 break; 75 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: 76 str = "incomplete read buffer"; 77 break; 78 case GL_FRAMEBUFFER_UNSUPPORTED: 79 str = "unsupported"; 80 break; 81 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: 82 str = "incomplete multiple"; 83 break; 84 default: 85 str = "unknown error"; 86 break; 87 } 88 89 glamor_fallback("glamor: Failed to create fbo, %s\n", str); 90 err = -1; 91 } 92 93 return err; 94} 95 96glamor_pixmap_fbo * 97glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv, 98 int w, int h, GLenum format, GLint tex, int flag) 99{ 100 glamor_pixmap_fbo *fbo; 101 102 fbo = calloc(1, sizeof(*fbo)); 103 if (fbo == NULL) 104 return NULL; 105 106 fbo->tex = tex; 107 fbo->width = w; 108 fbo->height = h; 109 fbo->format = format; 110 111 if (flag != GLAMOR_CREATE_FBO_NO_FBO) { 112 if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) { 113 glamor_destroy_fbo(glamor_priv, fbo); 114 fbo = NULL; 115 } 116 } 117 118 return fbo; 119} 120 121static int 122_glamor_create_tex(glamor_screen_private *glamor_priv, 123 int w, int h, GLenum format) 124{ 125 unsigned int tex; 126 GLenum iformat = format; 127 128 if (format == GL_RGB10_A2) 129 format = GL_RGBA; 130 glamor_make_current(glamor_priv); 131 glGenTextures(1, &tex); 132 glBindTexture(GL_TEXTURE_2D, tex); 133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 135 if (format == glamor_priv->one_channel_format && format == GL_RED) 136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED); 137 glamor_priv->suppress_gl_out_of_memory_logging = true; 138 glTexImage2D(GL_TEXTURE_2D, 0, iformat, w, h, 0, 139 format, GL_UNSIGNED_BYTE, NULL); 140 glamor_priv->suppress_gl_out_of_memory_logging = false; 141 142 if (glGetError() == GL_OUT_OF_MEMORY) { 143 if (!glamor_priv->logged_any_fbo_allocation_failure) { 144 LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %dx%d " 145 "FBO due to GL_OUT_OF_MEMORY.\n", w, h); 146 LogMessageVerb(X_WARNING, 0, 147 "glamor: Expect reduced performance.\n"); 148 glamor_priv->logged_any_fbo_allocation_failure = true; 149 } 150 glDeleteTextures(1, &tex); 151 return 0; 152 } 153 154 return tex; 155} 156 157glamor_pixmap_fbo * 158glamor_create_fbo(glamor_screen_private *glamor_priv, 159 int w, int h, GLenum format, int flag) 160{ 161 GLint tex = _glamor_create_tex(glamor_priv, w, h, format); 162 163 if (!tex) /* Texture creation failed due to GL_OUT_OF_MEMORY */ 164 return NULL; 165 166 return glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag); 167} 168 169/** 170 * Create storage for the w * h region, using FBOs of the GL's maximum 171 * supported size. 172 */ 173glamor_pixmap_fbo * 174glamor_create_fbo_array(glamor_screen_private *glamor_priv, 175 int w, int h, GLenum format, int flag, 176 int block_w, int block_h, 177 glamor_pixmap_private *priv) 178{ 179 int block_wcnt; 180 int block_hcnt; 181 glamor_pixmap_fbo **fbo_array; 182 BoxPtr box_array; 183 int i, j; 184 185 priv->block_w = block_w; 186 priv->block_h = block_h; 187 188 block_wcnt = (w + block_w - 1) / block_w; 189 block_hcnt = (h + block_h - 1) / block_h; 190 191 box_array = calloc(block_wcnt * block_hcnt, sizeof(box_array[0])); 192 if (box_array == NULL) 193 return NULL; 194 195 fbo_array = calloc(block_wcnt * block_hcnt, sizeof(glamor_pixmap_fbo *)); 196 if (fbo_array == NULL) { 197 free(box_array); 198 return FALSE; 199 } 200 for (i = 0; i < block_hcnt; i++) { 201 int block_y1, block_y2; 202 int fbo_w, fbo_h; 203 204 block_y1 = i * block_h; 205 block_y2 = (block_y1 + block_h) > h ? h : (block_y1 + block_h); 206 fbo_h = block_y2 - block_y1; 207 208 for (j = 0; j < block_wcnt; j++) { 209 box_array[i * block_wcnt + j].x1 = j * block_w; 210 box_array[i * block_wcnt + j].y1 = block_y1; 211 box_array[i * block_wcnt + j].x2 = 212 (j + 1) * block_w > w ? w : (j + 1) * block_w; 213 box_array[i * block_wcnt + j].y2 = block_y2; 214 fbo_w = 215 box_array[i * block_wcnt + j].x2 - box_array[i * block_wcnt + 216 j].x1; 217 fbo_array[i * block_wcnt + j] = glamor_create_fbo(glamor_priv, 218 fbo_w, fbo_h, 219 format, 220 GLAMOR_CREATE_PIXMAP_FIXUP); 221 if (fbo_array[i * block_wcnt + j] == NULL) 222 goto cleanup; 223 } 224 } 225 226 priv->box = box_array[0]; 227 priv->box_array = box_array; 228 priv->fbo_array = fbo_array; 229 priv->block_wcnt = block_wcnt; 230 priv->block_hcnt = block_hcnt; 231 return fbo_array[0]; 232 233 cleanup: 234 for (i = 0; i < block_wcnt * block_hcnt; i++) 235 if (fbo_array[i]) 236 glamor_destroy_fbo(glamor_priv, fbo_array[i]); 237 free(box_array); 238 free(fbo_array); 239 return NULL; 240} 241 242glamor_pixmap_fbo * 243glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv) 244{ 245 glamor_pixmap_fbo *fbo; 246 247 if (pixmap_priv == NULL) 248 return NULL; 249 250 fbo = pixmap_priv->fbo; 251 if (fbo == NULL) 252 return NULL; 253 254 pixmap_priv->fbo = NULL; 255 return fbo; 256} 257 258/* The pixmap must not be attached to another fbo. */ 259void 260glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo) 261{ 262 glamor_pixmap_private *pixmap_priv; 263 264 pixmap_priv = glamor_get_pixmap_private(pixmap); 265 266 if (pixmap_priv->fbo) 267 return; 268 269 pixmap_priv->fbo = fbo; 270 271 switch (pixmap_priv->type) { 272 case GLAMOR_TEXTURE_ONLY: 273 case GLAMOR_TEXTURE_DRM: 274 pixmap_priv->gl_fbo = GLAMOR_FBO_NORMAL; 275 pixmap->devPrivate.ptr = NULL; 276 default: 277 break; 278 } 279} 280 281void 282glamor_pixmap_destroy_fbo(PixmapPtr pixmap) 283{ 284 ScreenPtr screen = pixmap->drawable.pScreen; 285 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 286 glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 287 glamor_pixmap_fbo *fbo; 288 289 if (glamor_pixmap_priv_is_large(priv)) { 290 int i; 291 292 for (i = 0; i < priv->block_wcnt * priv->block_hcnt; i++) 293 glamor_destroy_fbo(glamor_priv, priv->fbo_array[i]); 294 free(priv->fbo_array); 295 priv->fbo_array = NULL; 296 } 297 else { 298 fbo = glamor_pixmap_detach_fbo(priv); 299 if (fbo) 300 glamor_destroy_fbo(glamor_priv, fbo); 301 } 302} 303 304Bool 305glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag) 306{ 307 glamor_screen_private *glamor_priv; 308 glamor_pixmap_private *pixmap_priv; 309 glamor_pixmap_fbo *fbo; 310 311 glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); 312 pixmap_priv = glamor_get_pixmap_private(pixmap); 313 if (pixmap_priv->fbo == NULL) { 314 315 fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width, 316 pixmap->drawable.height, format, flag); 317 if (fbo == NULL) 318 return FALSE; 319 320 glamor_pixmap_attach_fbo(pixmap, fbo); 321 } 322 else { 323 /* We do have a fbo, but it may lack of fb or tex. */ 324 if (!pixmap_priv->fbo->tex) 325 pixmap_priv->fbo->tex = 326 _glamor_create_tex(glamor_priv, pixmap->drawable.width, 327 pixmap->drawable.height, format); 328 329 if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0) 330 if (glamor_pixmap_ensure_fb(glamor_priv, pixmap_priv->fbo) != 0) 331 return FALSE; 332 } 333 334 return TRUE; 335} 336 337_X_EXPORT void 338glamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back) 339{ 340 glamor_pixmap_private *front_priv, *back_priv; 341 glamor_pixmap_fbo *temp_fbo; 342 343 front_priv = glamor_get_pixmap_private(front); 344 back_priv = glamor_get_pixmap_private(back); 345 temp_fbo = front_priv->fbo; 346 front_priv->fbo = back_priv->fbo; 347 back_priv->fbo = temp_fbo; 348} 349