/** * We only implement this function as a mechanism to check if the * framebuffer size has changed (and update corresponding state). */ static void gl_ggiViewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h) { GLuint newWidth, newHeight; GLframebuffer *buffer = ctx->WinSysDrawBuffer; gl_ggiGetSize( buffer, &newWidth, &newHeight ); if (buffer->Width != newWidth || buffer->Height != newHeight) { _mesa_resize_framebuffer(ctx, buffer, newWidth, newHeight ); } }
/** * Update cliprects and scissors. */ void radeonSetCliprects(radeonContextPtr radeon) { __DRIdrawablePrivate *const drawable = radeon->dri.drawable; __DRIdrawablePrivate *const readable = radeon->dri.readable; GLframebuffer *const draw_fb = (GLframebuffer*)drawable->driverPrivate; GLframebuffer *const read_fb = (GLframebuffer*)readable->driverPrivate; if (draw_fb->_ColorDrawBufferMask[0] == BUFFER_BIT_BACK_LEFT) { /* Can't ignore 2d windows if we are page flipping. */ if (drawable->numBackClipRects == 0 || radeon->doPageFlip || radeon->sarea->pfCurrentPage == 1) { radeon->numClipRects = drawable->numClipRects; radeon->pClipRects = drawable->pClipRects; } else { radeon->numClipRects = drawable->numBackClipRects; radeon->pClipRects = drawable->pBackClipRects; } } else { /* front buffer (or none, or multiple buffers */ radeon->numClipRects = drawable->numClipRects; radeon->pClipRects = drawable->pClipRects; } if ((draw_fb->Width != drawable->w) || (draw_fb->Height != drawable->h)) { _mesa_resize_framebuffer(radeon->glCtx, draw_fb, drawable->w, drawable->h); draw_fb->Initialized = GL_TRUE; } if (drawable != readable) { if ((read_fb->Width != readable->w) || (read_fb->Height != readable->h)) { _mesa_resize_framebuffer(radeon->glCtx, read_fb, readable->w, readable->h); read_fb->Initialized = GL_TRUE; } } if (radeon->state.scissor.enabled) radeonRecalcScissorRects(radeon); radeon->lastStamp = drawable->lastStamp; }
static void swrast_check_and_update_window_size( struct gl_context *ctx, struct gl_framebuffer *fb ) { GLsizei width, height; get_window_size(fb, &width, &height); if (fb->Width != width || fb->Height != height) { _mesa_resize_framebuffer(ctx, fb, width, height); } }
/** * For GLX_EXT_texture_from_pixmap */ XMesaBuffer XMesaCreatePixmapTextureBuffer(XMesaVisual v, XMesaPixmap p, XMesaColormap cmap, int format, int target, int mipmap) { GET_CURRENT_CONTEXT(ctx); XMesaBuffer b; GLuint width, height; assert(v); b = create_xmesa_buffer((XMesaDrawable) p, PIXMAP, v, cmap); if (!b) return NULL; /* get pixmap size, update framebuffer/renderbuffer dims */ xmesa_get_window_size(v->display, b, &width, &height); _mesa_resize_framebuffer(NULL, &(b->mesa_buffer), width, height); if (target == 0) { /* examine dims */ if (ctx->Extensions.ARB_texture_non_power_of_two) { target = GLX_TEXTURE_2D_EXT; } else if ( _mesa_bitcount(width) == 1 && _mesa_bitcount(height) == 1) { /* power of two size */ if (height == 1) { target = GLX_TEXTURE_1D_EXT; } else { target = GLX_TEXTURE_2D_EXT; } } else if (ctx->Extensions.NV_texture_rectangle) { target = GLX_TEXTURE_RECTANGLE_EXT; } else { /* non power of two textures not supported */ XMesaDestroyBuffer(b); return 0; } } b->TextureTarget = target; b->TextureFormat = format; b->TextureMipmap = mipmap; if (!initialize_visual_and_buffer(v, b, (XMesaDrawable) p, cmap)) { xmesa_free_buffer(b); return NULL; } return b; }
/** * Check that the gl_framebuffer associated with dPriv is the right size. * Resize the gl_framebuffer if needed. * It's expected that the dPriv->driverPrivate member points to a * gl_framebuffer object. */ void driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv) { struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate; if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) { _mesa_resize_framebuffer(ctx, fb, dPriv->w, dPriv->h); /* if the driver needs the hw lock for ResizeBuffers, the drawable might have changed again by now */ assert(fb->Width == dPriv->w); assert(fb->Height == dPriv->h); } }
/** * Query the current window size and update the corresponding struct gl_framebuffer * and all attached renderbuffers. * Called when: * 1. the first time a buffer is bound to a context. * 2. from glViewport to poll for window size changes * 3. from the XMesaResizeBuffers() API function. * Note: it's possible (and legal) for xmctx to be NULL. That can happen * when resizing a buffer when no rendering context is bound. */ void xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer) { GLuint width, height; xmesa_get_window_size(drawBuffer->display, drawBuffer, &width, &height); if (drawBuffer->mesa_buffer.Width != width || drawBuffer->mesa_buffer.Height != height) { struct gl_context *ctx = xmctx ? &xmctx->mesa : NULL; _mesa_resize_framebuffer(ctx, &(drawBuffer->mesa_buffer), width, height); } drawBuffer->mesa_buffer.Initialized = GL_TRUE; /* XXX TEMPORARY? */ }
/** * Make sure a context picks up the latest cached state of the * drawables it binds to. */ static void st_context_validate(struct st_context *st, struct st_framebuffer *stdraw, struct st_framebuffer *stread) { if (stdraw && stdraw->stamp != st->draw_stamp) { st->dirty.st |= ST_NEW_FRAMEBUFFER; _mesa_resize_framebuffer(st->ctx, &stdraw->Base, stdraw->Base.Width, stdraw->Base.Height); st->draw_stamp = stdraw->stamp; } if (stread && stread->stamp != st->read_stamp) { if (stread != stdraw) { st->dirty.st |= ST_NEW_FRAMEBUFFER; _mesa_resize_framebuffer(st->ctx, &stread->Base, stread->Base.Width, stread->Base.Height); } st->read_stamp = stread->stamp; } }
static void hgl_viewport(struct gl_context* glContext) { // TODO: We should try to eliminate this function GLint x = glContext->ViewportArray[0].X; GLint y = glContext->ViewportArray[0].Y; GLint width = glContext->ViewportArray[0].Width; GLint height = glContext->ViewportArray[0].Height; TRACE("%s(glContext: %p, x: %d, y: %d, w: %d, h: %d\n", __func__, glContext, x, y, width, height); _mesa_check_init_viewport(glContext, width, height); struct gl_framebuffer *draw = glContext->WinSysDrawBuffer; struct gl_framebuffer *read = glContext->WinSysReadBuffer; if (draw) _mesa_resize_framebuffer(glContext, draw, width, height); if (read) _mesa_resize_framebuffer(glContext, read, width, height); }
/* * Bind an OSMesaContext to an image buffer. The image buffer is just a * block of memory which the client provides. Its size must be at least * as large as width*height*sizeof(type). Its address should be a multiple * of 4 if using RGBA mode. * * Image data is stored in the order of glDrawPixels: row-major order * with the lower-left image pixel stored in the first array position * (ie. bottom-to-top). * * If the context's viewport hasn't been initialized yet, it will now be * initialized to (0,0,width,height). * * Input: ctx - the rendering context * buffer - the image buffer memory * type - data type for pixel components * Normally, only GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT_5_6_5 * are supported. But if Mesa's been compiled with CHAN_BITS==16 * then type must be GL_UNSIGNED_SHORT. And if Mesa's been build * with CHAN_BITS==32 then type must be GL_FLOAT. * width, height - size of image buffer in pixels, at least 1 * Return: GL_TRUE if success, GL_FALSE if error because of invalid ctx, * invalid buffer address, invalid type, width<1, height<1, * width>internal limit or height>internal limit. */ GLAPI GLboolean GLAPIENTRY OSMesaMakeCurrent( OSMesaContext ctx, void *buffer, GLenum type, GLsizei width, GLsizei height ) { if (!ctx || !buffer || width < 1 || height < 1 || width > MAX_WIDTH || height > MAX_HEIGHT) { return GL_FALSE; } if (ctx->format == OSMESA_RGB_565) { if (type != GL_UNSIGNED_SHORT_5_6_5) return GL_FALSE; } else if (type != CHAN_TYPE) { return GL_FALSE; } /* Need to set these before calling _mesa_make_current() since the first * time the context is bound, _mesa_make_current() will call our * get_buffer_size() function to initialize the viewport. These are the * values returned by get_buffer_size(): */ ctx->buffer = buffer; ctx->width = width; ctx->height = height; osmesa_update_state( &ctx->mesa, 0 ); /* Call this periodically to detect when the user has begun using * GL rendering from multiple threads. */ _glapi_check_multithread(); _mesa_make_current( &ctx->mesa, ctx->gl_buffer, ctx->gl_buffer ); if (ctx->userRowLength) ctx->rowlength = ctx->userRowLength; else ctx->rowlength = width; compute_row_addresses( ctx ); /* this will make ensure we recognize the new buffer size */ _mesa_resize_framebuffer(&ctx->mesa, ctx->gl_buffer, width, height); return GL_TRUE; }
static EGLSurface fbCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { fbSurface *surf; surf = (fbSurface *) calloc(1, sizeof(fbSurface)); if (!surf) { return EGL_NO_SURFACE; } if (_eglInitPbufferSurface(&surf->Base, drv, dpy, config, attrib_list) == EGL_NO_SURFACE) { free(surf); return EGL_NO_SURFACE; } /* create software-based pbuffer */ { GLcontext *ctx = NULL; /* this _should_ be OK */ GLvisual vis; _EGLConfig *conf = _eglLookupConfig(drv, dpy, config); assert(conf); /* bad config should be caught earlier */ _eglConfigToContextModesRec(conf, &vis); surf->mesa_framebuffer = _mesa_create_framebuffer(&vis); _mesa_add_soft_renderbuffers(surf->mesa_framebuffer, GL_TRUE, /* color bufs */ vis.haveDepthBuffer, vis.haveStencilBuffer, vis.haveAccumBuffer, GL_FALSE, /* alpha */ GL_FALSE /* aux */ ); /* set pbuffer/framebuffer size */ _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer, surf->Base.Width, surf->Base.Height); } return surf->Base.Handle; }
/* Update the hardware state. This is called if another context has * grabbed the hardware lock, which includes the X server. This * function also updates the driver's window state after the X server * moves, resizes or restacks a window -- the change will be reflected * in the drawable position and clip rects. Since the X server grabs * the hardware lock when it changes the window state, this routine will * automatically be called after such a change. */ void nouveauGetLock( nouveauContextPtr nmesa, GLuint flags ) { __DRIdrawablePrivate *dPriv = nmesa->driDrawable; __DRIscreenPrivate *sPriv = nmesa->driScreen; drm_nouveau_sarea_t *sarea = nmesa->sarea; drmGetLock( nmesa->driFd, nmesa->hHWContext, flags ); /* The window might have moved, so we might need to get new clip * rects. * * NOTE: This releases and regrabs the hw lock to allow the X server * to respond to the DRI protocol request for new drawable info. * Since the hardware state depends on having the latest drawable * clip rects, all state checking must be done _after_ this call. */ DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv ); /* If timestamps don't match, the window has been changed */ if (nmesa->lastStamp != dPriv->lastStamp) { struct gl_framebuffer *fb = (struct gl_framebuffer *)dPriv->driverPrivate; /* _mesa_resize_framebuffer will take care of calling the renderbuffer's * AllocStorage function if we need more memory to hold it */ if (fb->Width != dPriv->w || fb->Height != dPriv->h) { _mesa_resize_framebuffer(nmesa->glCtx, fb, dPriv->w, dPriv->h); /* resize buffers, will call nouveau_window_moved */ nouveau_build_framebuffer(nmesa->glCtx, fb); } else { nouveau_window_moved(nmesa->glCtx); } nmesa->lastStamp = dPriv->lastStamp; } nmesa->numClipRects = dPriv->numClipRects; nmesa->pClipRects = dPriv->pClipRects; }
void MesaSoftwareRenderer::_AllocateBitmap() { // allocate new size of back buffer bitmap delete fBitmap; fBitmap = NULL; if (fWidth < 1 || fHeight < 1) return; BRect rect(0.0, 0.0, fWidth - 1, fHeight - 1); fBitmap = new BBitmap(rect, fColorSpace); for (uint i = 0; i < fHeight; i++) { fRowAddr[fHeight - i - 1] = (GLvoid *)((GLubyte *)fBitmap->Bits() + i * fBitmap->BytesPerRow()); } _mesa_resize_framebuffer(fContext, &fFrameBuffer->Base, fWidth, fHeight); fFrontRenderBuffer->Base.Data = fBitmap->Bits(); fFrontRenderBuffer->Size = fBitmap->BitsLength(); fBackRenderBuffer->Size = fBitmap->BitsLength(); fFrameBuffer->Width = fWidth; fFrameBuffer->Height = fHeight; }
/** * Validate a framebuffer to make sure up-to-date pipe_textures are used. * The context we need to pass in is s dummy context needed only to be * able to get a pipe context to create pipe surfaces, and to have a * context to call _mesa_resize_framebuffer(): * (That should probably be rethought, since those surfaces become * drawable state, not context state, and can be freed by another pipe * context). */ static void st_framebuffer_validate(struct st_framebuffer *stfb, struct st_context *st) { struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; uint width, height; unsigned i; boolean changed = FALSE; int32_t new_stamp = p_atomic_read(&stfb->iface->stamp); if (stfb->iface_stamp == new_stamp) return; /* validate the fb */ do { if (!stfb->iface->validate(stfb->iface, stfb->statts, stfb->num_statts, textures)) return; stfb->iface_stamp = new_stamp; new_stamp = p_atomic_read(&stfb->iface->stamp); } while(stfb->iface_stamp != new_stamp); width = stfb->Base.Width; height = stfb->Base.Height; for (i = 0; i < stfb->num_statts; i++) { struct st_renderbuffer *strb; struct pipe_surface *ps, surf_tmpl; gl_buffer_index idx; if (!textures[i]) continue; idx = attachment_to_buffer_index(stfb->statts[i]); if (idx >= BUFFER_COUNT) { pipe_resource_reference(&textures[i], NULL); continue; } strb = st_renderbuffer(stfb->Base.Attachment[idx].Renderbuffer); assert(strb); if (strb->texture == textures[i]) { pipe_resource_reference(&textures[i], NULL); continue; } u_surface_default_template(&surf_tmpl, textures[i], PIPE_BIND_RENDER_TARGET); ps = st->pipe->create_surface(st->pipe, textures[i], &surf_tmpl); if (ps) { pipe_surface_reference(&strb->surface, ps); pipe_resource_reference(&strb->texture, ps->texture); /* ownership transfered */ pipe_surface_reference(&ps, NULL); changed = TRUE; strb->Base.Width = strb->surface->width; strb->Base.Height = strb->surface->height; width = strb->Base.Width; height = strb->Base.Height; } pipe_resource_reference(&textures[i], NULL); } if (changed) { ++stfb->stamp; _mesa_resize_framebuffer(st->ctx, &stfb->Base, width, height); } }
/** * Create a drawing surface which can be directly displayed on a screen. */ static EGLSurface fbCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg, const EGLint *attrib_list) { _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg); fbDisplay *display = Lookup_fbDisplay(dpy); fbSurface *surface; EGLSurface surf; GLvisual vis; GLcontext *ctx = NULL; /* this should be OK */ int origin, bytesPerPixel; int width, height, stride; surface = (fbSurface *) malloc(sizeof(*surface)); if (!surface) { return EGL_NO_SURFACE; } /* init base class, error check, etc. */ surf = _eglInitScreenSurface(&surface->Base, drv, dpy, cfg, attrib_list); if (surf == EGL_NO_SURFACE) { free(surface); return EGL_NO_SURFACE; } /* convert EGLConfig to GLvisual */ _eglConfigToContextModesRec(config, &vis); /* create Mesa framebuffer */ surface->mesa_framebuffer = _mesa_create_framebuffer(&vis); if (!surface->mesa_framebuffer) { free(surface); _eglRemoveSurface(&surface->Base); return EGL_NO_SURFACE; } width = surface->Base.Width; height = surface->Base.Height; bytesPerPixel = vis.rgbBits / 8; stride = width * bytesPerPixel; origin = 0; /* front color renderbuffer */ { driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, display->pFB, bytesPerPixel, origin, stride, NULL); fbSetSpanFunctions(drb, &vis); _mesa_add_renderbuffer(surface->mesa_framebuffer, BUFFER_FRONT_LEFT, &drb->Base); } /* back color renderbuffer */ if (vis.doubleBufferMode) { GLubyte *backBuf = _mesa_malloc(stride * height); driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, backBuf, bytesPerPixel, origin, stride, NULL); fbSetSpanFunctions(drb, &vis); _mesa_add_renderbuffer(surface->mesa_framebuffer, BUFFER_BACK_LEFT, &drb->Base); } /* other renderbuffers- software based */ _mesa_add_soft_renderbuffers(surface->mesa_framebuffer, GL_FALSE, /* color */ vis.haveDepthBuffer, vis.haveStencilBuffer, vis.haveAccumBuffer, GL_FALSE, /* alpha */ GL_FALSE /* aux */); _mesa_resize_framebuffer(ctx, surface->mesa_framebuffer, width, height); return surf; }
/** * Bind an OSMesaContext to an image buffer. The image buffer is just a * block of memory which the client provides. Its size must be at least * as large as width*height*sizeof(type). Its address should be a multiple * of 4 if using RGBA mode. * * Image data is stored in the order of glDrawPixels: row-major order * with the lower-left image pixel stored in the first array position * (ie. bottom-to-top). * * If the context's viewport hasn't been initialized yet, it will now be * initialized to (0,0,width,height). * * Input: osmesa - the rendering context * buffer - the image buffer memory * type - data type for pixel components * Normally, only GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT_5_6_5 * are supported. But if Mesa's been compiled with CHAN_BITS==16 * then type may be GL_UNSIGNED_SHORT or GL_UNSIGNED_BYTE. And if * Mesa's been build with CHAN_BITS==32 then type may be GL_FLOAT, * GL_UNSIGNED_SHORT or GL_UNSIGNED_BYTE. * width, height - size of image buffer in pixels, at least 1 * Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa, * invalid buffer address, invalid type, width<1, height<1, * width>internal limit or height>internal limit. */ GLAPI GLboolean GLAPIENTRY OSMesaMakeCurrent( OSMesaContext osmesa, void *buffer, GLenum type, GLsizei width, GLsizei height ) { if (!osmesa || !buffer || width < 1 || height < 1 || width > SWRAST_MAX_WIDTH || height > SWRAST_MAX_HEIGHT) { return GL_FALSE; } if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) { return GL_FALSE; } #if 0 if (!(type == GL_UNSIGNED_BYTE || (type == GL_UNSIGNED_SHORT && CHAN_BITS >= 16) || (type == GL_FLOAT && CHAN_BITS == 32))) { /* i.e. is sizeof(type) * 8 > CHAN_BITS? */ return GL_FALSE; } #endif osmesa_update_state( &osmesa->mesa, 0 ); /* Call this periodically to detect when the user has begun using * GL rendering from multiple threads. */ _glapi_check_multithread(); /* Create a front/left color buffer which wraps the user-provided buffer. * There is no back color buffer. * If the user tries to use a 8, 16 or 32-bit/channel buffer that * doesn't match what Mesa was compiled for (CHAN_BITS) the * _mesa_add_renderbuffer() function will create a "wrapper" renderbuffer * that converts rendering from CHAN_BITS to the user-requested channel * size. */ if (!osmesa->srb) { osmesa->srb = new_osmesa_renderbuffer(&osmesa->mesa, osmesa->format, type); _mesa_remove_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT); _mesa_add_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT, &osmesa->srb->Base); assert(osmesa->srb->Base.RefCount == 2); } osmesa->DataType = type; /* Set renderbuffer fields. Set width/height = 0 to force * osmesa_renderbuffer_storage() being called by _mesa_resize_framebuffer() */ osmesa->srb->Buffer = buffer; osmesa->srb->Base.Width = osmesa->srb->Base.Height = 0; /* Set the framebuffer's size. This causes the * osmesa_renderbuffer_storage() function to get called. */ _mesa_resize_framebuffer(&osmesa->mesa, osmesa->gl_buffer, width, height); osmesa->gl_buffer->Initialized = GL_TRUE; /* XXX TEMPORARY? */ _mesa_make_current( &osmesa->mesa, osmesa->gl_buffer, osmesa->gl_buffer ); /* Remove renderbuffer attachment, then re-add. This installs the * renderbuffer adaptor/wrapper if needed (for bpp conversion). */ _mesa_remove_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT); _mesa_add_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT, &osmesa->srb->Base); /* this updates the visual's red/green/blue/alphaBits fields */ _mesa_update_framebuffer_visual(&osmesa->mesa, osmesa->gl_buffer); /* update the framebuffer size */ _mesa_resize_framebuffer(&osmesa->mesa, osmesa->gl_buffer, width, height); return GL_TRUE; }
BOOL sw_SetContext(struct wgl_dc_data* dc_data, DHGLRC dhglrc) { struct sw_context* sw_ctx = (struct sw_context*)dhglrc; struct sw_framebuffer* fb = dc_data->sw_data; UINT width, height; /* Update state */ sw_update_state(&sw_ctx->mesa, 0); /* Get framebuffer size */ if(dc_data->flags & WGL_DC_OBJ_DC) { HWND hwnd = dc_data->owner.hwnd; RECT client_rect; if(!hwnd) { ERR("Physical DC without a window!\n"); return FALSE; } if(!GetClientRect(hwnd, &client_rect)) { ERR("GetClientRect failed!\n"); return FALSE; } /* This is a physical DC. Setup the hook */ sw_ctx->hook = SetWindowsHookEx(WH_CALLWNDPROC, sw_call_window_proc, NULL, GetCurrentThreadId()); /* Calculate width & height */ width = client_rect.right - client_rect.left; height = client_rect.bottom - client_rect.top; } else /* OBJ_MEMDC */ { BITMAP bm; HBITMAP hbmp; HDC hdc = dc_data->owner.hdc; if(fb->flags & SW_FB_DOUBLEBUFFERED) { ERR("Memory DC called with a double buffered format.\n"); return FALSE; } hbmp = GetCurrentObject( hdc, OBJ_BITMAP ); if(!hbmp) { ERR("No Bitmap!\n"); return FALSE; } if(GetObject(hbmp, sizeof(bm), &bm) == 0) { ERR("GetObject failed!\n"); return FALSE; } width = bm.bmWidth; height = bm.bmHeight; } if(!width) width = 1; if(!height) height = 1; fb->bmi.bmiHeader.biWidth = width; fb->bmi.bmiHeader.biHeight = height; /* Also make the mesa context current to mesa */ if(!_mesa_make_current(&sw_ctx->mesa, fb->gl_buffer, fb->gl_buffer)) { ERR("_mesa_make_current filaed!\n"); return FALSE; } /* Set the viewport if this is the first time we initialize this context */ if(sw_ctx->mesa.Viewport.X == 0 && sw_ctx->mesa.Viewport.Y == 0 && sw_ctx->mesa.Viewport.Width == 0 && sw_ctx->mesa.Viewport.Height == 0) { _mesa_set_viewport(&sw_ctx->mesa, 0, 0, width, height); } /* update the framebuffer size */ _mesa_resize_framebuffer(&sw_ctx->mesa, fb->gl_buffer, width, height); /* We're good */ return TRUE; }