135c4bbdfSmrg/* 235c4bbdfSmrg * Copyright © 2009 Intel Corporation 335c4bbdfSmrg * Copyright © 1998 Keith Packard 435c4bbdfSmrg * 535c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a 635c4bbdfSmrg * copy of this software and associated documentation files (the "Software"), 735c4bbdfSmrg * to deal in the Software without restriction, including without limitation 835c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 935c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the 1035c4bbdfSmrg * Software is furnished to do so, subject to the following conditions: 1135c4bbdfSmrg * 1235c4bbdfSmrg * The above copyright notice and this permission notice (including the next 1335c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the 1435c4bbdfSmrg * Software. 1535c4bbdfSmrg * 1635c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1735c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1835c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1935c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2035c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2135c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2235c4bbdfSmrg * IN THE SOFTWARE. 2335c4bbdfSmrg * 2435c4bbdfSmrg * Authors: 2535c4bbdfSmrg * Zhigang Gong <zhigang.gong@gmail.com> 2635c4bbdfSmrg * 2735c4bbdfSmrg */ 2835c4bbdfSmrg 2935c4bbdfSmrg#include <stdlib.h> 3035c4bbdfSmrg 3135c4bbdfSmrg#include "glamor_priv.h" 3235c4bbdfSmrg 331b5d61b8Smrgvoid 341b5d61b8Smrgglamor_destroy_fbo(glamor_screen_private *glamor_priv, 351b5d61b8Smrg glamor_pixmap_fbo *fbo) 3635c4bbdfSmrg{ 3735c4bbdfSmrg glamor_make_current(glamor_priv); 3835c4bbdfSmrg 3935c4bbdfSmrg if (fbo->fb) 4035c4bbdfSmrg glDeleteFramebuffers(1, &fbo->fb); 4135c4bbdfSmrg if (fbo->tex) 4235c4bbdfSmrg glDeleteTextures(1, &fbo->tex); 4335c4bbdfSmrg 4435c4bbdfSmrg free(fbo); 4535c4bbdfSmrg} 4635c4bbdfSmrg 4735c4bbdfSmrgstatic int 4835c4bbdfSmrgglamor_pixmap_ensure_fb(glamor_screen_private *glamor_priv, 4935c4bbdfSmrg glamor_pixmap_fbo *fbo) 5035c4bbdfSmrg{ 5135c4bbdfSmrg int status, err = 0; 5235c4bbdfSmrg 5335c4bbdfSmrg glamor_make_current(glamor_priv); 5435c4bbdfSmrg 5535c4bbdfSmrg if (fbo->fb == 0) 5635c4bbdfSmrg glGenFramebuffers(1, &fbo->fb); 5735c4bbdfSmrg assert(fbo->tex != 0); 5835c4bbdfSmrg glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); 5935c4bbdfSmrg glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 6035c4bbdfSmrg GL_TEXTURE_2D, fbo->tex, 0); 6135c4bbdfSmrg status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 6235c4bbdfSmrg if (status != GL_FRAMEBUFFER_COMPLETE) { 6335c4bbdfSmrg const char *str; 6435c4bbdfSmrg 6535c4bbdfSmrg switch (status) { 6635c4bbdfSmrg case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 6735c4bbdfSmrg str = "incomplete attachment"; 6835c4bbdfSmrg break; 6935c4bbdfSmrg case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 7035c4bbdfSmrg str = "incomplete/missing attachment"; 7135c4bbdfSmrg break; 7235c4bbdfSmrg case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: 7335c4bbdfSmrg str = "incomplete draw buffer"; 7435c4bbdfSmrg break; 7535c4bbdfSmrg case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: 7635c4bbdfSmrg str = "incomplete read buffer"; 7735c4bbdfSmrg break; 7835c4bbdfSmrg case GL_FRAMEBUFFER_UNSUPPORTED: 7935c4bbdfSmrg str = "unsupported"; 8035c4bbdfSmrg break; 8135c4bbdfSmrg case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: 8235c4bbdfSmrg str = "incomplete multiple"; 8335c4bbdfSmrg break; 8435c4bbdfSmrg default: 8535c4bbdfSmrg str = "unknown error"; 8635c4bbdfSmrg break; 8735c4bbdfSmrg } 8835c4bbdfSmrg 8935c4bbdfSmrg glamor_fallback("glamor: Failed to create fbo, %s\n", str); 9035c4bbdfSmrg err = -1; 9135c4bbdfSmrg } 9235c4bbdfSmrg 9335c4bbdfSmrg return err; 9435c4bbdfSmrg} 9535c4bbdfSmrg 9635c4bbdfSmrgglamor_pixmap_fbo * 9735c4bbdfSmrgglamor_create_fbo_from_tex(glamor_screen_private *glamor_priv, 98ed6184dfSmrg PixmapPtr pixmap, int w, int h, GLint tex, int flag) 9935c4bbdfSmrg{ 100ed6184dfSmrg const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 10135c4bbdfSmrg glamor_pixmap_fbo *fbo; 10235c4bbdfSmrg 10335c4bbdfSmrg fbo = calloc(1, sizeof(*fbo)); 10435c4bbdfSmrg if (fbo == NULL) 10535c4bbdfSmrg return NULL; 10635c4bbdfSmrg 10735c4bbdfSmrg fbo->tex = tex; 10835c4bbdfSmrg fbo->width = w; 10935c4bbdfSmrg fbo->height = h; 110ed6184dfSmrg fbo->is_red = f->format == GL_RED; 11135c4bbdfSmrg 11235c4bbdfSmrg if (flag != GLAMOR_CREATE_FBO_NO_FBO) { 11335c4bbdfSmrg if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) { 1141b5d61b8Smrg glamor_destroy_fbo(glamor_priv, fbo); 11535c4bbdfSmrg fbo = NULL; 11635c4bbdfSmrg } 11735c4bbdfSmrg } 11835c4bbdfSmrg 11935c4bbdfSmrg return fbo; 12035c4bbdfSmrg} 12135c4bbdfSmrg 12235c4bbdfSmrgstatic int 12335c4bbdfSmrg_glamor_create_tex(glamor_screen_private *glamor_priv, 124ed6184dfSmrg PixmapPtr pixmap, int w, int h) 12535c4bbdfSmrg{ 126ed6184dfSmrg const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 12735c4bbdfSmrg unsigned int tex; 12835c4bbdfSmrg 12935c4bbdfSmrg glamor_make_current(glamor_priv); 13035c4bbdfSmrg glGenTextures(1, &tex); 13135c4bbdfSmrg glBindTexture(GL_TEXTURE_2D, tex); 13235c4bbdfSmrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 13335c4bbdfSmrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 134ed6184dfSmrg if (f->format == GL_RED) 13535c4bbdfSmrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED); 13635c4bbdfSmrg glamor_priv->suppress_gl_out_of_memory_logging = true; 137ed6184dfSmrg glTexImage2D(GL_TEXTURE_2D, 0, f->internalformat, w, h, 0, 138ed6184dfSmrg f->format, f->type, NULL); 13935c4bbdfSmrg glamor_priv->suppress_gl_out_of_memory_logging = false; 14035c4bbdfSmrg 14135c4bbdfSmrg if (glGetError() == GL_OUT_OF_MEMORY) { 14235c4bbdfSmrg if (!glamor_priv->logged_any_fbo_allocation_failure) { 14335c4bbdfSmrg LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %dx%d " 14435c4bbdfSmrg "FBO due to GL_OUT_OF_MEMORY.\n", w, h); 14535c4bbdfSmrg LogMessageVerb(X_WARNING, 0, 14635c4bbdfSmrg "glamor: Expect reduced performance.\n"); 14735c4bbdfSmrg glamor_priv->logged_any_fbo_allocation_failure = true; 14835c4bbdfSmrg } 14935c4bbdfSmrg glDeleteTextures(1, &tex); 15035c4bbdfSmrg return 0; 15135c4bbdfSmrg } 15235c4bbdfSmrg 15335c4bbdfSmrg return tex; 15435c4bbdfSmrg} 15535c4bbdfSmrg 15635c4bbdfSmrgglamor_pixmap_fbo * 15735c4bbdfSmrgglamor_create_fbo(glamor_screen_private *glamor_priv, 158ed6184dfSmrg PixmapPtr pixmap, int w, int h, int flag) 15935c4bbdfSmrg{ 160ed6184dfSmrg GLint tex = _glamor_create_tex(glamor_priv, pixmap, w, h); 16135c4bbdfSmrg 1621b5d61b8Smrg if (!tex) /* Texture creation failed due to GL_OUT_OF_MEMORY */ 16335c4bbdfSmrg return NULL; 16435c4bbdfSmrg 165ed6184dfSmrg return glamor_create_fbo_from_tex(glamor_priv, pixmap, w, h, 166ed6184dfSmrg tex, flag); 16735c4bbdfSmrg} 16835c4bbdfSmrg 16935c4bbdfSmrg/** 17035c4bbdfSmrg * Create storage for the w * h region, using FBOs of the GL's maximum 17135c4bbdfSmrg * supported size. 17235c4bbdfSmrg */ 17335c4bbdfSmrgglamor_pixmap_fbo * 17435c4bbdfSmrgglamor_create_fbo_array(glamor_screen_private *glamor_priv, 175ed6184dfSmrg PixmapPtr pixmap, int flag, 17635c4bbdfSmrg int block_w, int block_h, 17735c4bbdfSmrg glamor_pixmap_private *priv) 17835c4bbdfSmrg{ 179ed6184dfSmrg int w = pixmap->drawable.width; 180ed6184dfSmrg int h = pixmap->drawable.height; 18135c4bbdfSmrg int block_wcnt; 18235c4bbdfSmrg int block_hcnt; 18335c4bbdfSmrg glamor_pixmap_fbo **fbo_array; 18435c4bbdfSmrg BoxPtr box_array; 18535c4bbdfSmrg int i, j; 18635c4bbdfSmrg 18735c4bbdfSmrg priv->block_w = block_w; 18835c4bbdfSmrg priv->block_h = block_h; 18935c4bbdfSmrg 19035c4bbdfSmrg block_wcnt = (w + block_w - 1) / block_w; 19135c4bbdfSmrg block_hcnt = (h + block_h - 1) / block_h; 19235c4bbdfSmrg 19335c4bbdfSmrg box_array = calloc(block_wcnt * block_hcnt, sizeof(box_array[0])); 19435c4bbdfSmrg if (box_array == NULL) 19535c4bbdfSmrg return NULL; 19635c4bbdfSmrg 19735c4bbdfSmrg fbo_array = calloc(block_wcnt * block_hcnt, sizeof(glamor_pixmap_fbo *)); 19835c4bbdfSmrg if (fbo_array == NULL) { 19935c4bbdfSmrg free(box_array); 20035c4bbdfSmrg return FALSE; 20135c4bbdfSmrg } 20235c4bbdfSmrg for (i = 0; i < block_hcnt; i++) { 20335c4bbdfSmrg int block_y1, block_y2; 20435c4bbdfSmrg int fbo_w, fbo_h; 20535c4bbdfSmrg 20635c4bbdfSmrg block_y1 = i * block_h; 20735c4bbdfSmrg block_y2 = (block_y1 + block_h) > h ? h : (block_y1 + block_h); 20835c4bbdfSmrg fbo_h = block_y2 - block_y1; 20935c4bbdfSmrg 21035c4bbdfSmrg for (j = 0; j < block_wcnt; j++) { 21135c4bbdfSmrg box_array[i * block_wcnt + j].x1 = j * block_w; 21235c4bbdfSmrg box_array[i * block_wcnt + j].y1 = block_y1; 21335c4bbdfSmrg box_array[i * block_wcnt + j].x2 = 21435c4bbdfSmrg (j + 1) * block_w > w ? w : (j + 1) * block_w; 21535c4bbdfSmrg box_array[i * block_wcnt + j].y2 = block_y2; 21635c4bbdfSmrg fbo_w = 21735c4bbdfSmrg box_array[i * block_wcnt + j].x2 - box_array[i * block_wcnt + 21835c4bbdfSmrg j].x1; 21935c4bbdfSmrg fbo_array[i * block_wcnt + j] = glamor_create_fbo(glamor_priv, 220ed6184dfSmrg pixmap, 22135c4bbdfSmrg fbo_w, fbo_h, 22235c4bbdfSmrg GLAMOR_CREATE_PIXMAP_FIXUP); 22335c4bbdfSmrg if (fbo_array[i * block_wcnt + j] == NULL) 22435c4bbdfSmrg goto cleanup; 22535c4bbdfSmrg } 22635c4bbdfSmrg } 22735c4bbdfSmrg 22835c4bbdfSmrg priv->box = box_array[0]; 22935c4bbdfSmrg priv->box_array = box_array; 23035c4bbdfSmrg priv->fbo_array = fbo_array; 23135c4bbdfSmrg priv->block_wcnt = block_wcnt; 23235c4bbdfSmrg priv->block_hcnt = block_hcnt; 23335c4bbdfSmrg return fbo_array[0]; 23435c4bbdfSmrg 23535c4bbdfSmrg cleanup: 23635c4bbdfSmrg for (i = 0; i < block_wcnt * block_hcnt; i++) 23735c4bbdfSmrg if (fbo_array[i]) 23835c4bbdfSmrg glamor_destroy_fbo(glamor_priv, fbo_array[i]); 23935c4bbdfSmrg free(box_array); 24035c4bbdfSmrg free(fbo_array); 24135c4bbdfSmrg return NULL; 24235c4bbdfSmrg} 24335c4bbdfSmrg 2445a7dfde8Smrgvoid 245ed6184dfSmrgglamor_pixmap_clear_fbo(glamor_screen_private *glamor_priv, glamor_pixmap_fbo *fbo, 246ed6184dfSmrg const struct glamor_format *pixmap_format) 2475a7dfde8Smrg{ 2485a7dfde8Smrg glamor_make_current(glamor_priv); 2495a7dfde8Smrg 2505a7dfde8Smrg assert(fbo->fb != 0 && fbo->tex != 0); 2515a7dfde8Smrg 252ed6184dfSmrg if (glamor_priv->has_clear_texture) { 253ed6184dfSmrg glClearTexImage(fbo->tex, 0, pixmap_format->format, pixmap_format->type, NULL); 254ed6184dfSmrg } 255ed6184dfSmrg else { 256ed6184dfSmrg glamor_set_destination_pixmap_fbo(glamor_priv, fbo, 0, 0, fbo->width, fbo->height); 257ed6184dfSmrg 258ed6184dfSmrg glClearColor(0.0, 0.0, 0.0, 0.0); 259ed6184dfSmrg glClear(GL_COLOR_BUFFER_BIT); 260ed6184dfSmrg } 2615a7dfde8Smrg} 2625a7dfde8Smrg 26335c4bbdfSmrgglamor_pixmap_fbo * 26435c4bbdfSmrgglamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv) 26535c4bbdfSmrg{ 26635c4bbdfSmrg glamor_pixmap_fbo *fbo; 26735c4bbdfSmrg 26835c4bbdfSmrg if (pixmap_priv == NULL) 26935c4bbdfSmrg return NULL; 27035c4bbdfSmrg 27135c4bbdfSmrg fbo = pixmap_priv->fbo; 27235c4bbdfSmrg if (fbo == NULL) 27335c4bbdfSmrg return NULL; 27435c4bbdfSmrg 27535c4bbdfSmrg pixmap_priv->fbo = NULL; 27635c4bbdfSmrg return fbo; 27735c4bbdfSmrg} 27835c4bbdfSmrg 27935c4bbdfSmrg/* The pixmap must not be attached to another fbo. */ 28035c4bbdfSmrgvoid 28135c4bbdfSmrgglamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo) 28235c4bbdfSmrg{ 28335c4bbdfSmrg glamor_pixmap_private *pixmap_priv; 28435c4bbdfSmrg 28535c4bbdfSmrg pixmap_priv = glamor_get_pixmap_private(pixmap); 28635c4bbdfSmrg 28735c4bbdfSmrg if (pixmap_priv->fbo) 28835c4bbdfSmrg return; 28935c4bbdfSmrg 29035c4bbdfSmrg pixmap_priv->fbo = fbo; 29135c4bbdfSmrg 29235c4bbdfSmrg switch (pixmap_priv->type) { 29335c4bbdfSmrg case GLAMOR_TEXTURE_ONLY: 29435c4bbdfSmrg case GLAMOR_TEXTURE_DRM: 29535c4bbdfSmrg pixmap_priv->gl_fbo = GLAMOR_FBO_NORMAL; 29635c4bbdfSmrg pixmap->devPrivate.ptr = NULL; 29735c4bbdfSmrg default: 29835c4bbdfSmrg break; 29935c4bbdfSmrg } 30035c4bbdfSmrg} 30135c4bbdfSmrg 30235c4bbdfSmrgvoid 30335c4bbdfSmrgglamor_pixmap_destroy_fbo(PixmapPtr pixmap) 30435c4bbdfSmrg{ 30535c4bbdfSmrg ScreenPtr screen = pixmap->drawable.pScreen; 30635c4bbdfSmrg glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 30735c4bbdfSmrg glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 30835c4bbdfSmrg glamor_pixmap_fbo *fbo; 30935c4bbdfSmrg 31035c4bbdfSmrg if (glamor_pixmap_priv_is_large(priv)) { 31135c4bbdfSmrg int i; 31235c4bbdfSmrg 31335c4bbdfSmrg for (i = 0; i < priv->block_wcnt * priv->block_hcnt; i++) 31435c4bbdfSmrg glamor_destroy_fbo(glamor_priv, priv->fbo_array[i]); 31535c4bbdfSmrg free(priv->fbo_array); 3161b5d61b8Smrg priv->fbo_array = NULL; 31735c4bbdfSmrg } 31835c4bbdfSmrg else { 31935c4bbdfSmrg fbo = glamor_pixmap_detach_fbo(priv); 32035c4bbdfSmrg if (fbo) 32135c4bbdfSmrg glamor_destroy_fbo(glamor_priv, fbo); 32235c4bbdfSmrg } 32335c4bbdfSmrg} 32435c4bbdfSmrg 32535c4bbdfSmrgBool 326ed6184dfSmrgglamor_pixmap_ensure_fbo(PixmapPtr pixmap, int flag) 32735c4bbdfSmrg{ 32835c4bbdfSmrg glamor_screen_private *glamor_priv; 32935c4bbdfSmrg glamor_pixmap_private *pixmap_priv; 33035c4bbdfSmrg glamor_pixmap_fbo *fbo; 33135c4bbdfSmrg 33235c4bbdfSmrg glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); 33335c4bbdfSmrg pixmap_priv = glamor_get_pixmap_private(pixmap); 33435c4bbdfSmrg if (pixmap_priv->fbo == NULL) { 33535c4bbdfSmrg 336ed6184dfSmrg fbo = glamor_create_fbo(glamor_priv, pixmap, pixmap->drawable.width, 337ed6184dfSmrg pixmap->drawable.height, flag); 33835c4bbdfSmrg if (fbo == NULL) 33935c4bbdfSmrg return FALSE; 34035c4bbdfSmrg 34135c4bbdfSmrg glamor_pixmap_attach_fbo(pixmap, fbo); 34235c4bbdfSmrg } 34335c4bbdfSmrg else { 34435c4bbdfSmrg /* We do have a fbo, but it may lack of fb or tex. */ 34535c4bbdfSmrg if (!pixmap_priv->fbo->tex) 34635c4bbdfSmrg pixmap_priv->fbo->tex = 347ed6184dfSmrg _glamor_create_tex(glamor_priv, pixmap, pixmap->drawable.width, 348ed6184dfSmrg pixmap->drawable.height); 34935c4bbdfSmrg 35035c4bbdfSmrg if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0) 35135c4bbdfSmrg if (glamor_pixmap_ensure_fb(glamor_priv, pixmap_priv->fbo) != 0) 35235c4bbdfSmrg return FALSE; 35335c4bbdfSmrg } 35435c4bbdfSmrg 35535c4bbdfSmrg return TRUE; 35635c4bbdfSmrg} 35735c4bbdfSmrg 35835c4bbdfSmrg_X_EXPORT void 35935c4bbdfSmrgglamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back) 36035c4bbdfSmrg{ 36135c4bbdfSmrg glamor_pixmap_private *front_priv, *back_priv; 36235c4bbdfSmrg glamor_pixmap_fbo *temp_fbo; 36335c4bbdfSmrg 36435c4bbdfSmrg front_priv = glamor_get_pixmap_private(front); 36535c4bbdfSmrg back_priv = glamor_get_pixmap_private(back); 36635c4bbdfSmrg temp_fbo = front_priv->fbo; 36735c4bbdfSmrg front_priv->fbo = back_priv->fbo; 36835c4bbdfSmrg back_priv->fbo = temp_fbo; 36935c4bbdfSmrg} 370