intel_fbo.c revision 6d2e1f6a2cd25107ad9bd88b1decd05fc8000f78
1/**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29#include "main/imports.h"
30#include "main/macros.h"
31#include "main/mtypes.h"
32#include "main/fbobject.h"
33#include "main/framebuffer.h"
34#include "main/renderbuffer.h"
35#include "main/context.h"
36#include "main/texformat.h"
37#include "main/texrender.h"
38
39#include "intel_context.h"
40#include "intel_buffers.h"
41#include "intel_depthstencil.h"
42#include "intel_fbo.h"
43#include "intel_mipmap_tree.h"
44#include "intel_regions.h"
45#include "intel_span.h"
46
47
48#define FILE_DEBUG_FLAG DEBUG_FBO
49
50
51/**
52 * Create a new framebuffer object.
53 */
54static struct gl_framebuffer *
55intel_new_framebuffer(GLcontext * ctx, GLuint name)
56{
57   /* Only drawable state in intel_framebuffer at this time, just use Mesa's
58    * class
59    */
60   return _mesa_new_framebuffer(ctx, name);
61}
62
63
64static void
65intel_delete_renderbuffer(struct gl_renderbuffer *rb)
66{
67   GET_CURRENT_CONTEXT(ctx);
68   struct intel_context *intel = intel_context(ctx);
69   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
70
71   ASSERT(irb);
72
73   if (irb->span_cache != NULL)
74      _mesa_free(irb->span_cache);
75
76   if (intel && irb->region) {
77      intel_region_release(&irb->region);
78   }
79
80   _mesa_free(irb);
81}
82
83
84
85/**
86 * Return a pointer to a specific pixel in a renderbuffer.
87 */
88static void *
89intel_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb,
90                  GLint x, GLint y)
91{
92   /* By returning NULL we force all software rendering to go through
93    * the span routines.
94    */
95   return NULL;
96}
97
98
99
100/**
101 * Called via glRenderbufferStorageEXT() to set the format and allocate
102 * storage for a user-created renderbuffer.
103 */
104static GLboolean
105intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
106                                 GLenum internalFormat,
107                                 GLuint width, GLuint height)
108{
109   struct intel_context *intel = intel_context(ctx);
110   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
111   GLboolean softwareBuffer = GL_FALSE;
112   int cpp;
113
114   ASSERT(rb->Name != 0);
115
116   switch (internalFormat) {
117   case GL_R3_G3_B2:
118   case GL_RGB4:
119   case GL_RGB5:
120      rb->_ActualFormat = GL_RGB5;
121      rb->DataType = GL_UNSIGNED_BYTE;
122      rb->RedBits = 5;
123      rb->GreenBits = 6;
124      rb->BlueBits = 5;
125      cpp = 2;
126      break;
127   case GL_RGB:
128   case GL_RGB8:
129   case GL_RGB10:
130   case GL_RGB12:
131   case GL_RGB16:
132      rb->_ActualFormat = GL_RGB8;
133      rb->DataType = GL_UNSIGNED_BYTE;
134      rb->RedBits = 8;
135      rb->GreenBits = 8;
136      rb->BlueBits = 8;
137      rb->AlphaBits = 0;
138      cpp = 4;
139      break;
140   case GL_RGBA:
141   case GL_RGBA2:
142   case GL_RGBA4:
143   case GL_RGB5_A1:
144   case GL_RGBA8:
145   case GL_RGB10_A2:
146   case GL_RGBA12:
147   case GL_RGBA16:
148      rb->_ActualFormat = GL_RGBA8;
149      rb->DataType = GL_UNSIGNED_BYTE;
150      rb->RedBits = 8;
151      rb->GreenBits = 8;
152      rb->BlueBits = 8;
153      rb->AlphaBits = 8;
154      cpp = 4;
155      break;
156   case GL_STENCIL_INDEX:
157   case GL_STENCIL_INDEX1_EXT:
158   case GL_STENCIL_INDEX4_EXT:
159   case GL_STENCIL_INDEX8_EXT:
160   case GL_STENCIL_INDEX16_EXT:
161      /* alloc a depth+stencil buffer */
162      rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
163      rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
164      rb->StencilBits = 8;
165      cpp = 4;
166      break;
167   case GL_DEPTH_COMPONENT16:
168      rb->_ActualFormat = GL_DEPTH_COMPONENT16;
169      rb->DataType = GL_UNSIGNED_SHORT;
170      rb->DepthBits = 16;
171      cpp = 2;
172      break;
173   case GL_DEPTH_COMPONENT:
174   case GL_DEPTH_COMPONENT24:
175   case GL_DEPTH_COMPONENT32:
176      rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
177      rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
178      rb->DepthBits = 24;
179      cpp = 4;
180      break;
181   case GL_DEPTH_STENCIL_EXT:
182   case GL_DEPTH24_STENCIL8_EXT:
183      rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
184      rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
185      rb->DepthBits = 24;
186      rb->StencilBits = 8;
187      cpp = 4;
188      break;
189   default:
190      _mesa_problem(ctx,
191                    "Unexpected format in intel_alloc_renderbuffer_storage");
192      return GL_FALSE;
193   }
194
195   intelFlush(ctx);
196
197   /* free old region */
198   if (irb->region) {
199      intel_region_release(&irb->region);
200   }
201
202   /* allocate new memory region/renderbuffer */
203   if (softwareBuffer) {
204      return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat,
205                                             width, height);
206   }
207   else {
208      /* Choose a pitch to match hardware requirements:
209       */
210      GLuint pitch = ((cpp * width + 63) & ~63) / cpp;
211
212      /* alloc hardware renderbuffer */
213      DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width,
214	  height, pitch);
215
216      irb->region = intel_region_alloc(intel, cpp, width, height, pitch);
217      if (!irb->region)
218         return GL_FALSE;       /* out of memory? */
219
220      ASSERT(irb->region->buffer);
221
222      rb->Width = width;
223      rb->Height = height;
224
225      return GL_TRUE;
226   }
227}
228
229
230
231/**
232 * Called for each hardware renderbuffer when a _window_ is resized.
233 * Just update fields.
234 * Not used for user-created renderbuffers!
235 */
236static GLboolean
237intel_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
238                           GLenum internalFormat, GLuint width, GLuint height)
239{
240   ASSERT(rb->Name == 0);
241   rb->Width = width;
242   rb->Height = height;
243   rb->_ActualFormat = internalFormat;
244
245   return GL_TRUE;
246}
247
248static void
249intel_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb,
250		     GLuint width, GLuint height)
251{
252   struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb;
253   int i;
254
255   _mesa_resize_framebuffer(ctx, fb, width, height);
256
257   fb->Initialized = GL_TRUE; /* XXX remove someday */
258
259   if (fb->Name != 0) {
260      return;
261   }
262
263   /* Make sure all window system renderbuffers are up to date */
264   for (i = 0; i < 2; i++) {
265      struct gl_renderbuffer *rb = &intel_fb->color_rb[i]->Base;
266
267      /* only resize if size is changing */
268      if (rb && (rb->Width != width || rb->Height != height)) {
269	 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height);
270      }
271   }
272}
273
274static GLboolean
275intel_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
276                        GLenum internalFormat, GLuint width, GLuint height)
277{
278   _mesa_problem(ctx, "intel_op_alloc_storage should never be called.");
279   return GL_FALSE;
280}
281
282
283void
284intel_renderbuffer_set_region(struct intel_renderbuffer *rb,
285			      struct intel_region *region)
286{
287   struct intel_region *old;
288
289   old = rb->region;
290   rb->region = NULL;
291   intel_region_reference(&rb->region, region);
292   intel_region_release(&old);
293
294   rb->pfPitch = region->pitch;
295}
296
297/**
298 * Create a new intel_renderbuffer which corresponds to an on-screen window,
299 * not a user-created renderbuffer.
300 */
301struct intel_renderbuffer *
302intel_create_renderbuffer(GLenum intFormat)
303{
304   GET_CURRENT_CONTEXT(ctx);
305
306   struct intel_renderbuffer *irb;
307   const GLuint name = 0;
308
309   irb = CALLOC_STRUCT(intel_renderbuffer);
310   if (!irb) {
311      _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
312      return NULL;
313   }
314
315   _mesa_init_renderbuffer(&irb->Base, name);
316   irb->Base.ClassID = INTEL_RB_CLASS;
317
318   switch (intFormat) {
319   case GL_RGB5:
320      irb->Base._ActualFormat = GL_RGB5;
321      irb->Base._BaseFormat = GL_RGBA;
322      irb->Base.RedBits = 5;
323      irb->Base.GreenBits = 6;
324      irb->Base.BlueBits = 5;
325      irb->Base.DataType = GL_UNSIGNED_BYTE;
326      break;
327   case GL_RGBA8:
328      irb->Base._ActualFormat = GL_RGBA8;
329      irb->Base._BaseFormat = GL_RGBA;
330      irb->Base.RedBits = 8;
331      irb->Base.GreenBits = 8;
332      irb->Base.BlueBits = 8;
333      irb->Base.AlphaBits = 8;
334      irb->Base.DataType = GL_UNSIGNED_BYTE;
335      break;
336   case GL_STENCIL_INDEX8_EXT:
337      irb->Base._ActualFormat = GL_STENCIL_INDEX8_EXT;
338      irb->Base._BaseFormat = GL_STENCIL_INDEX;
339      irb->Base.StencilBits = 8;
340      irb->Base.DataType = GL_UNSIGNED_BYTE;
341      break;
342   case GL_DEPTH_COMPONENT16:
343      irb->Base._ActualFormat = GL_DEPTH_COMPONENT16;
344      irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
345      irb->Base.DepthBits = 16;
346      irb->Base.DataType = GL_UNSIGNED_SHORT;
347      break;
348   case GL_DEPTH_COMPONENT24:
349      irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
350      irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
351      irb->Base.DepthBits = 24;
352      irb->Base.DataType = GL_UNSIGNED_INT;
353      break;
354   case GL_DEPTH24_STENCIL8_EXT:
355      irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
356      irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
357      irb->Base.DepthBits = 24;
358      irb->Base.StencilBits = 8;
359      irb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
360      break;
361   default:
362      _mesa_problem(NULL,
363                    "Unexpected intFormat in intel_create_renderbuffer");
364      return NULL;
365   }
366
367   irb->Base.InternalFormat = intFormat;
368
369   /* intel-specific methods */
370   irb->Base.Delete = intel_delete_renderbuffer;
371   irb->Base.AllocStorage = intel_alloc_window_storage;
372   irb->Base.GetPointer = intel_get_pointer;
373
374   return irb;
375}
376
377
378/**
379 * Create a new renderbuffer object.
380 * Typically called via glBindRenderbufferEXT().
381 */
382static struct gl_renderbuffer *
383intel_new_renderbuffer(GLcontext * ctx, GLuint name)
384{
385   /*struct intel_context *intel = intel_context(ctx); */
386   struct intel_renderbuffer *irb;
387
388   irb = CALLOC_STRUCT(intel_renderbuffer);
389   if (!irb) {
390      _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
391      return NULL;
392   }
393
394   _mesa_init_renderbuffer(&irb->Base, name);
395   irb->Base.ClassID = INTEL_RB_CLASS;
396
397   /* intel-specific methods */
398   irb->Base.Delete = intel_delete_renderbuffer;
399   irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
400   irb->Base.GetPointer = intel_get_pointer;
401   /* span routines set in alloc_storage function */
402
403   return &irb->Base;
404}
405
406
407/**
408 * Called via glBindFramebufferEXT().
409 */
410static void
411intel_bind_framebuffer(GLcontext * ctx, GLenum target,
412                       struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
413{
414   if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
415      intel_draw_buffer(ctx, fb);
416   }
417   else {
418      /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
419   }
420}
421
422
423/**
424 * Called via glFramebufferRenderbufferEXT().
425 */
426static void
427intel_framebuffer_renderbuffer(GLcontext * ctx,
428                               struct gl_framebuffer *fb,
429                               GLenum attachment, struct gl_renderbuffer *rb)
430{
431   DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0);
432
433   intelFlush(ctx);
434
435   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
436   intel_draw_buffer(ctx, fb);
437}
438
439static GLboolean
440intel_update_wrapper(GLcontext *ctx, struct intel_renderbuffer *irb,
441		     struct gl_texture_image *texImage)
442{
443   if (texImage->TexFormat == &_mesa_texformat_argb8888) {
444      irb->Base._ActualFormat = GL_RGBA8;
445      irb->Base._BaseFormat = GL_RGBA;
446      irb->Base.DataType = GL_UNSIGNED_BYTE;
447      DBG("Render to RGBA8 texture OK\n");
448   }
449   else if (texImage->TexFormat == &_mesa_texformat_rgb565) {
450      irb->Base._ActualFormat = GL_RGB5;
451      irb->Base._BaseFormat = GL_RGB;
452      irb->Base.DataType = GL_UNSIGNED_SHORT;
453      DBG("Render to RGB5 texture OK\n");
454   }
455   else if (texImage->TexFormat == &_mesa_texformat_z16) {
456      irb->Base._ActualFormat = GL_DEPTH_COMPONENT16;
457      irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
458      irb->Base.DataType = GL_UNSIGNED_SHORT;
459      DBG("Render to DEPTH16 texture OK\n");
460   }
461   else if (texImage->TexFormat == &_mesa_texformat_s8_z24) {
462      irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
463      irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
464      irb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
465      DBG("Render to DEPTH_STENCIL texture OK\n");
466   }
467   else {
468      DBG("Render to texture BAD FORMAT %d\n",
469	  texImage->TexFormat->MesaFormat);
470      return GL_FALSE;
471   }
472
473   irb->Base.InternalFormat = irb->Base._ActualFormat;
474   irb->Base.Width = texImage->Width;
475   irb->Base.Height = texImage->Height;
476   irb->Base.RedBits = texImage->TexFormat->RedBits;
477   irb->Base.GreenBits = texImage->TexFormat->GreenBits;
478   irb->Base.BlueBits = texImage->TexFormat->BlueBits;
479   irb->Base.AlphaBits = texImage->TexFormat->AlphaBits;
480   irb->Base.DepthBits = texImage->TexFormat->DepthBits;
481
482   irb->Base.Delete = intel_delete_renderbuffer;
483   irb->Base.AllocStorage = intel_nop_alloc_storage;
484
485   irb->RenderToTexture = GL_TRUE;
486
487   return GL_TRUE;
488}
489
490/**
491 * When glFramebufferTexture[123]D is called this function sets up the
492 * gl_renderbuffer wrapper around the texture image.
493 * This will have the region info needed for hardware rendering.
494 */
495static struct intel_renderbuffer *
496intel_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage)
497{
498   const GLuint name = ~0;      /* not significant, but distinct for debugging */
499   struct intel_renderbuffer *irb;
500
501   /* make an intel_renderbuffer to wrap the texture image */
502   irb = CALLOC_STRUCT(intel_renderbuffer);
503   if (!irb) {
504      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture");
505      return NULL;
506   }
507
508   _mesa_init_renderbuffer(&irb->Base, name);
509   irb->Base.ClassID = INTEL_RB_CLASS;
510
511   if (!intel_update_wrapper(ctx, irb, texImage)) {
512      _mesa_free(irb);
513      return NULL;
514   }
515
516   return irb;
517}
518
519
520/**
521 * Called by glFramebufferTexture[123]DEXT() (and other places) to
522 * prepare for rendering into texture memory.  This might be called
523 * many times to choose different texture levels, cube faces, etc
524 * before intel_finish_render_texture() is ever called.
525 */
526static void
527intel_render_texture(GLcontext * ctx,
528                     struct gl_framebuffer *fb,
529                     struct gl_renderbuffer_attachment *att)
530{
531   struct gl_texture_image *newImage
532      = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
533   struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
534   struct intel_texture_image *intel_image;
535   GLuint imageOffset;
536
537   (void) fb;
538
539   ASSERT(newImage);
540
541   if (newImage->Border != 0) {
542      /* Fallback on drawing to a texture with a border, which won't have a
543       * miptree.
544       */
545       _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
546       _mesa_render_texture(ctx, fb, att);
547       return;
548   } else if (!irb) {
549      irb = intel_wrap_texture(ctx, newImage);
550      if (irb) {
551         /* bind the wrapper to the attachment point */
552         _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base);
553      }
554      else {
555         /* fallback to software rendering */
556         _mesa_render_texture(ctx, fb, att);
557         return;
558      }
559   } if (!intel_update_wrapper(ctx, irb, newImage)) {
560       _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
561       _mesa_render_texture(ctx, fb, att);
562       return;
563   }
564
565   DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n",
566       _glthread_GetID(),
567       att->Texture->Name, newImage->Width, newImage->Height,
568       irb->Base.RefCount);
569
570   /* point the renderbufer's region to the texture image region */
571   intel_image = intel_texture_image(newImage);
572   if (irb->region != intel_image->mt->region) {
573      if (irb->region)
574	 intel_region_release(&irb->region);
575      intel_region_reference(&irb->region, intel_image->mt->region);
576   }
577
578   /* compute offset of the particular 2D image within the texture region */
579   imageOffset = intel_miptree_image_offset(intel_image->mt,
580                                            att->CubeMapFace,
581                                            att->TextureLevel);
582
583   if (att->Texture->Target == GL_TEXTURE_3D) {
584      const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt,
585                                                          att->TextureLevel);
586      imageOffset += offsets[att->Zoffset];
587   }
588
589   /* store that offset in the region */
590   intel_image->mt->region->draw_offset = imageOffset;
591
592   /* update drawing region, etc */
593   intel_draw_buffer(ctx, fb);
594}
595
596
597/**
598 * Called by Mesa when rendering to a texture is done.
599 */
600static void
601intel_finish_render_texture(GLcontext * ctx,
602                            struct gl_renderbuffer_attachment *att)
603{
604   struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
605
606   DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att->Texture->Name);
607
608   if (irb) {
609      /* just release the region */
610      intel_region_release(&irb->region);
611   }
612   else if (att->Renderbuffer) {
613      /* software fallback */
614      _mesa_finish_render_texture(ctx, att);
615      /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */
616   }
617}
618
619
620/**
621 * Do additional "completeness" testing of a framebuffer object.
622 */
623static void
624intel_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
625{
626   const struct intel_renderbuffer *depthRb =
627      intel_get_renderbuffer(fb, BUFFER_DEPTH);
628   const struct intel_renderbuffer *stencilRb =
629      intel_get_renderbuffer(fb, BUFFER_STENCIL);
630
631   if (stencilRb && stencilRb != depthRb) {
632      /* we only support combined depth/stencil buffers, not separate
633       * stencil buffers.
634       */
635      fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
636   }
637}
638
639
640/**
641 * Called from glBlitFramebuffer().
642 * For now, we're doing an approximation with glCopyPixels().
643 * XXX we need to bypass all the per-fragment operations, except scissor.
644 */
645static void
646intel_blit_framebuffer(GLcontext *ctx,
647                       GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
648                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
649                       GLbitfield mask, GLenum filter)
650{
651   const GLfloat xZoomSave = ctx->Pixel.ZoomX;
652   const GLfloat yZoomSave = ctx->Pixel.ZoomY;
653   GLsizei width, height;
654   GLfloat xFlip = 1.0F, yFlip = 1.0F;
655
656   if (srcX1 < srcX0) {
657      GLint tmp = srcX1;
658      srcX1 = srcX0;
659      srcX0 = tmp;
660      xFlip = -1.0F;
661   }
662
663   if (srcY1 < srcY0) {
664      GLint tmp = srcY1;
665      srcY1 = srcY0;
666      srcY0 = tmp;
667      yFlip = -1.0F;
668   }
669
670   width = srcX1 - srcX0;
671   height = srcY1 - srcY0;
672
673   ctx->Pixel.ZoomX = xFlip * (dstX1 - dstX0) / (srcX1 - srcY0);
674   ctx->Pixel.ZoomY = yFlip * (dstY1 - dstY0) / (srcY1 - srcY0);
675
676   if (ctx->Pixel.ZoomX < 0.0F) {
677      dstX0 = MAX2(dstX0, dstX1);
678   }
679   else {
680      dstX0 = MIN2(dstX0, dstX1);
681   }
682
683   if (ctx->Pixel.ZoomY < 0.0F) {
684      dstY0 = MAX2(dstY0, dstY1);
685   }
686   else {
687      dstY0 = MIN2(dstY0, dstY1);
688   }
689
690   if (mask & GL_COLOR_BUFFER_BIT) {
691      ctx->Driver.CopyPixels(ctx, srcX0, srcY0, width, height,
692                             dstX0, dstY0, GL_COLOR);
693   }
694   if (mask & GL_DEPTH_BUFFER_BIT) {
695      ctx->Driver.CopyPixels(ctx, srcX0, srcY0, width, height,
696                             dstX0, dstY0, GL_DEPTH);
697   }
698   if (mask & GL_STENCIL_BUFFER_BIT) {
699      ctx->Driver.CopyPixels(ctx, srcX0, srcY0, width, height,
700                             dstX0, dstY0, GL_STENCIL);
701   }
702
703   ctx->Pixel.ZoomX = xZoomSave;
704   ctx->Pixel.ZoomY = yZoomSave;
705}
706
707
708/**
709 * Do one-time context initializations related to GL_EXT_framebuffer_object.
710 * Hook in device driver functions.
711 */
712void
713intel_fbo_init(struct intel_context *intel)
714{
715   intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer;
716   intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer;
717   intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer;
718   intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer;
719   intel->ctx.Driver.RenderTexture = intel_render_texture;
720   intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture;
721   intel->ctx.Driver.ResizeBuffers = intel_resize_buffers;
722   intel->ctx.Driver.ValidateFramebuffer = intel_validate_framebuffer;
723   intel->ctx.Driver.BlitFramebuffer = intel_blit_framebuffer;
724}
725