17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
26c1f859d4Smrg#include "main/glheader.h"
27cdc920a0Smrg#include "main/condrender.h"
284a49301eSmrg#include "main/image.h"
29c1f859d4Smrg#include "main/macros.h"
30af69d88dSmrg#include "main/format_unpack.h"
31af69d88dSmrg#include "main/format_pack.h"
32af69d88dSmrg#include "main/condrender.h"
337117f1b4Smrg#include "s_context.h"
347117f1b4Smrg
357117f1b4Smrg
367117f1b4Smrg#define ABS(X)   ((X) < 0 ? -(X) : (X))
377117f1b4Smrg
387117f1b4Smrg
397117f1b4Smrg/**
407117f1b4Smrg * Generate a row resampler function for GL_NEAREST mode.
417117f1b4Smrg */
427117f1b4Smrg#define RESAMPLE(NAME, PIXELTYPE, SIZE)			\
437117f1b4Smrgstatic void						\
447117f1b4SmrgNAME(GLint srcWidth, GLint dstWidth,			\
457117f1b4Smrg     const GLvoid *srcBuffer, GLvoid *dstBuffer,	\
467117f1b4Smrg     GLboolean flip)					\
477117f1b4Smrg{							\
487117f1b4Smrg   const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
497117f1b4Smrg   PIXELTYPE *dst = (PIXELTYPE *) dstBuffer;		\
507117f1b4Smrg   GLint dstCol;					\
517117f1b4Smrg							\
527117f1b4Smrg   if (flip) {						\
537117f1b4Smrg      for (dstCol = 0; dstCol < dstWidth; dstCol++) {	\
547117f1b4Smrg         GLint srcCol = (dstCol * srcWidth) / dstWidth;	\
5501e04c3fSmrg         assert(srcCol >= 0);				\
5601e04c3fSmrg         assert(srcCol < srcWidth);			\
577117f1b4Smrg         srcCol = srcWidth - 1 - srcCol; /* flip */	\
587117f1b4Smrg         if (SIZE == 1) {				\
597117f1b4Smrg            dst[dstCol] = src[srcCol];			\
607117f1b4Smrg         }						\
617117f1b4Smrg         else if (SIZE == 2) {				\
627117f1b4Smrg            dst[dstCol*2+0] = src[srcCol*2+0];		\
637117f1b4Smrg            dst[dstCol*2+1] = src[srcCol*2+1];		\
647117f1b4Smrg         }						\
657117f1b4Smrg         else if (SIZE == 4) {				\
667117f1b4Smrg            dst[dstCol*4+0] = src[srcCol*4+0];		\
677117f1b4Smrg            dst[dstCol*4+1] = src[srcCol*4+1];		\
687117f1b4Smrg            dst[dstCol*4+2] = src[srcCol*4+2];		\
697117f1b4Smrg            dst[dstCol*4+3] = src[srcCol*4+3];		\
707117f1b4Smrg         }						\
717117f1b4Smrg      }							\
727117f1b4Smrg   }							\
737117f1b4Smrg   else {						\
747117f1b4Smrg      for (dstCol = 0; dstCol < dstWidth; dstCol++) {	\
757117f1b4Smrg         GLint srcCol = (dstCol * srcWidth) / dstWidth;	\
7601e04c3fSmrg         assert(srcCol >= 0);				\
7701e04c3fSmrg         assert(srcCol < srcWidth);			\
787117f1b4Smrg         if (SIZE == 1) {				\
797117f1b4Smrg            dst[dstCol] = src[srcCol];			\
807117f1b4Smrg         }						\
817117f1b4Smrg         else if (SIZE == 2) {				\
827117f1b4Smrg            dst[dstCol*2+0] = src[srcCol*2+0];		\
837117f1b4Smrg            dst[dstCol*2+1] = src[srcCol*2+1];		\
847117f1b4Smrg         }						\
857117f1b4Smrg         else if (SIZE == 4) {				\
867117f1b4Smrg            dst[dstCol*4+0] = src[srcCol*4+0];		\
877117f1b4Smrg            dst[dstCol*4+1] = src[srcCol*4+1];		\
887117f1b4Smrg            dst[dstCol*4+2] = src[srcCol*4+2];		\
897117f1b4Smrg            dst[dstCol*4+3] = src[srcCol*4+3];		\
907117f1b4Smrg         }						\
917117f1b4Smrg      }							\
927117f1b4Smrg   }							\
937117f1b4Smrg}
947117f1b4Smrg
957117f1b4Smrg/**
967117f1b4Smrg * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
977117f1b4Smrg */
987117f1b4SmrgRESAMPLE(resample_row_1, GLubyte, 1)
997117f1b4SmrgRESAMPLE(resample_row_2, GLushort, 1)
1007117f1b4SmrgRESAMPLE(resample_row_4, GLuint, 1)
1017117f1b4SmrgRESAMPLE(resample_row_8, GLuint, 2)
1027117f1b4SmrgRESAMPLE(resample_row_16, GLuint, 4)
1037117f1b4Smrg
1047117f1b4Smrg
1057117f1b4Smrg/**
1067117f1b4Smrg * Blit color, depth or stencil with GL_NEAREST filtering.
1077117f1b4Smrg */
1087117f1b4Smrgstatic void
1093464ebd5Sriastradhblit_nearest(struct gl_context *ctx,
11001e04c3fSmrg             struct gl_framebuffer *readFb,
11101e04c3fSmrg             struct gl_framebuffer *drawFb,
1127117f1b4Smrg             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1137117f1b4Smrg             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1144a49301eSmrg             GLbitfield buffer)
1157117f1b4Smrg{
116af69d88dSmrg   struct gl_renderbuffer *readRb, *drawRb = NULL;
117af69d88dSmrg   struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL;
118af69d88dSmrg   GLuint numDrawBuffers = 0;
119af69d88dSmrg   GLuint i;
1207117f1b4Smrg
1217117f1b4Smrg   const GLint srcWidth = ABS(srcX1 - srcX0);
1227117f1b4Smrg   const GLint dstWidth = ABS(dstX1 - dstX0);
1237117f1b4Smrg   const GLint srcHeight = ABS(srcY1 - srcY0);
1247117f1b4Smrg   const GLint dstHeight = ABS(dstY1 - dstY0);
1257117f1b4Smrg
1267117f1b4Smrg   const GLint srcXpos = MIN2(srcX0, srcX1);
1277117f1b4Smrg   const GLint srcYpos = MIN2(srcY0, srcY1);
1287117f1b4Smrg   const GLint dstXpos = MIN2(dstX0, dstX1);
1297117f1b4Smrg   const GLint dstYpos = MIN2(dstY0, dstY1);
1307117f1b4Smrg
1317117f1b4Smrg   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
1327117f1b4Smrg   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
133af69d88dSmrg   enum mode {
134af69d88dSmrg      DIRECT,
135af69d88dSmrg      UNPACK_RGBA_FLOAT,
136af69d88dSmrg      UNPACK_Z_FLOAT,
137af69d88dSmrg      UNPACK_Z_INT,
138af69d88dSmrg      UNPACK_S,
139af69d88dSmrg   } mode = DIRECT;
140af69d88dSmrg   GLubyte *srcMap, *dstMap;
141af69d88dSmrg   GLint srcRowStride, dstRowStride;
1427117f1b4Smrg   GLint dstRow;
1437117f1b4Smrg
144af69d88dSmrg   GLint pixelSize = 0;
1457117f1b4Smrg   GLvoid *srcBuffer, *dstBuffer;
1467117f1b4Smrg   GLint prevY = -1;
1477117f1b4Smrg
1487117f1b4Smrg   typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
1497117f1b4Smrg                                 const GLvoid *srcBuffer, GLvoid *dstBuffer,
1507117f1b4Smrg                                 GLboolean flip);
1517117f1b4Smrg   resample_func resampleRow;
1527117f1b4Smrg
1537117f1b4Smrg   switch (buffer) {
1547117f1b4Smrg   case GL_COLOR_BUFFER_BIT:
155af69d88dSmrg      readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
156af69d88dSmrg      readRb = readFb->_ColorReadBuffer;
157af69d88dSmrg      numDrawBuffers = drawFb->_NumColorDrawBuffers;
1587117f1b4Smrg      break;
1597117f1b4Smrg   case GL_DEPTH_BUFFER_BIT:
160af69d88dSmrg      readAtt = &readFb->Attachment[BUFFER_DEPTH];
161af69d88dSmrg      drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
162af69d88dSmrg      readRb = readAtt->Renderbuffer;
163af69d88dSmrg      drawRb = drawAtt->Renderbuffer;
164af69d88dSmrg      numDrawBuffers = 1;
165af69d88dSmrg
166af69d88dSmrg      /* Note that for depth/stencil, the formats of src/dst must match.  By
167af69d88dSmrg       * using the core helpers for pack/unpack, we avoid needing to handle
168af69d88dSmrg       * masking for things like DEPTH copies of Z24S8.
169af69d88dSmrg       */
170af69d88dSmrg      if (readRb->Format == MESA_FORMAT_Z_FLOAT32 ||
171af69d88dSmrg	  readRb->Format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) {
172af69d88dSmrg	 mode = UNPACK_Z_FLOAT;
173af69d88dSmrg      } else {
174af69d88dSmrg	 mode = UNPACK_Z_INT;
175af69d88dSmrg      }
176af69d88dSmrg      pixelSize = 4;
1777117f1b4Smrg      break;
1787117f1b4Smrg   case GL_STENCIL_BUFFER_BIT:
179af69d88dSmrg      readAtt = &readFb->Attachment[BUFFER_STENCIL];
180af69d88dSmrg      drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
181af69d88dSmrg      readRb = readAtt->Renderbuffer;
182af69d88dSmrg      drawRb = drawAtt->Renderbuffer;
183af69d88dSmrg      numDrawBuffers = 1;
184af69d88dSmrg      mode = UNPACK_S;
185af69d88dSmrg      pixelSize = 1;
1867117f1b4Smrg      break;
1877117f1b4Smrg   default:
1887117f1b4Smrg      _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
1897117f1b4Smrg      return;
1907117f1b4Smrg   }
1917117f1b4Smrg
1927117f1b4Smrg   /* allocate the src/dst row buffers */
193af69d88dSmrg   srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth);
194af69d88dSmrg   dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth);
195af69d88dSmrg   if (!srcBuffer || !dstBuffer)
196af69d88dSmrg      goto fail_no_memory;
197af69d88dSmrg
198af69d88dSmrg   /* Blit to all the draw buffers */
199af69d88dSmrg   for (i = 0; i < numDrawBuffers; i++) {
200af69d88dSmrg      if (buffer == GL_COLOR_BUFFER_BIT) {
20101e04c3fSmrg         gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i];
20201e04c3fSmrg         if (idx == BUFFER_NONE)
203af69d88dSmrg            continue;
204af69d88dSmrg         drawAtt = &drawFb->Attachment[idx];
205af69d88dSmrg         drawRb = drawAtt->Renderbuffer;
206af69d88dSmrg
207af69d88dSmrg         if (!drawRb)
208af69d88dSmrg            continue;
209af69d88dSmrg
210af69d88dSmrg         if (readRb->Format == drawRb->Format) {
211af69d88dSmrg            mode = DIRECT;
212af69d88dSmrg            pixelSize = _mesa_get_format_bytes(readRb->Format);
213af69d88dSmrg         } else {
214af69d88dSmrg            mode = UNPACK_RGBA_FLOAT;
215af69d88dSmrg            pixelSize = 16;
216af69d88dSmrg         }
217af69d88dSmrg      }
218af69d88dSmrg
219af69d88dSmrg      /* choose row resampler */
220af69d88dSmrg      switch (pixelSize) {
221af69d88dSmrg      case 1:
222af69d88dSmrg         resampleRow = resample_row_1;
223af69d88dSmrg         break;
224af69d88dSmrg      case 2:
225af69d88dSmrg         resampleRow = resample_row_2;
226af69d88dSmrg         break;
227af69d88dSmrg      case 4:
228af69d88dSmrg         resampleRow = resample_row_4;
229af69d88dSmrg         break;
230af69d88dSmrg      case 8:
231af69d88dSmrg         resampleRow = resample_row_8;
232af69d88dSmrg         break;
233af69d88dSmrg      case 16:
234af69d88dSmrg         resampleRow = resample_row_16;
235af69d88dSmrg         break;
236af69d88dSmrg      default:
237af69d88dSmrg         _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
238af69d88dSmrg                       pixelSize);
239af69d88dSmrg         goto fail;
240af69d88dSmrg      }
2417117f1b4Smrg
242af69d88dSmrg      if ((readRb == drawRb) ||
243af69d88dSmrg          (readAtt->Texture && drawAtt->Texture &&
244af69d88dSmrg           (readAtt->Texture == drawAtt->Texture))) {
245af69d88dSmrg         /* map whole buffer for read/write */
246af69d88dSmrg         /* XXX we could be clever and just map the union region of the
247af69d88dSmrg          * source and dest rects.
248af69d88dSmrg          */
249af69d88dSmrg         GLubyte *map;
250af69d88dSmrg         GLint rowStride;
251af69d88dSmrg         GLint formatSize = _mesa_get_format_bytes(readRb->Format);
252af69d88dSmrg
253af69d88dSmrg         ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
254af69d88dSmrg                                     readRb->Width, readRb->Height,
255af69d88dSmrg                                     GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
25601e04c3fSmrg                                     &map, &rowStride, readFb->FlipY);
257af69d88dSmrg         if (!map) {
258af69d88dSmrg            goto fail_no_memory;
259af69d88dSmrg         }
2607117f1b4Smrg
261af69d88dSmrg         srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
262af69d88dSmrg         dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
2637117f1b4Smrg
264af69d88dSmrg         /* this handles overlapping copies */
265af69d88dSmrg         if (srcY0 < dstY0) {
266af69d88dSmrg            /* copy in reverse (top->down) order */
267af69d88dSmrg            srcMap += rowStride * (readRb->Height - 1);
268af69d88dSmrg            dstMap += rowStride * (readRb->Height - 1);
269af69d88dSmrg            srcRowStride = -rowStride;
270af69d88dSmrg            dstRowStride = -rowStride;
271af69d88dSmrg         }
272af69d88dSmrg         else {
273af69d88dSmrg            /* copy in normal (bottom->up) order */
274af69d88dSmrg            srcRowStride = rowStride;
275af69d88dSmrg            dstRowStride = rowStride;
276af69d88dSmrg         }
277af69d88dSmrg      }
278af69d88dSmrg      else {
279af69d88dSmrg         /* different src/dst buffers */
280af69d88dSmrg         ctx->Driver.MapRenderbuffer(ctx, readRb,
281af69d88dSmrg                                     srcXpos, srcYpos,
282af69d88dSmrg                                     srcWidth, srcHeight,
28301e04c3fSmrg                                     GL_MAP_READ_BIT, &srcMap, &srcRowStride,
28401e04c3fSmrg                                     readFb->FlipY);
285af69d88dSmrg         if (!srcMap) {
286af69d88dSmrg            goto fail_no_memory;
287af69d88dSmrg         }
288af69d88dSmrg         ctx->Driver.MapRenderbuffer(ctx, drawRb,
289af69d88dSmrg                                     dstXpos, dstYpos,
290af69d88dSmrg                                     dstWidth, dstHeight,
29101e04c3fSmrg                                     GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
29201e04c3fSmrg                                     drawFb->FlipY);
293af69d88dSmrg         if (!dstMap) {
294af69d88dSmrg            ctx->Driver.UnmapRenderbuffer(ctx, readRb);
295af69d88dSmrg            goto fail_no_memory;
296af69d88dSmrg         }
2977117f1b4Smrg      }
2987117f1b4Smrg
299af69d88dSmrg      for (dstRow = 0; dstRow < dstHeight; dstRow++) {
300af69d88dSmrg         GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
3017ec681f3Smrg         GLint srcRow = lroundf(srcRowF);
302af69d88dSmrg         GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
303af69d88dSmrg
30401e04c3fSmrg         assert(srcRow >= 0);
30501e04c3fSmrg         assert(srcRow < srcHeight);
306af69d88dSmrg
307af69d88dSmrg         if (invertY) {
308af69d88dSmrg            srcRow = srcHeight - 1 - srcRow;
309af69d88dSmrg         }
310af69d88dSmrg
311af69d88dSmrg         /* get pixel row from source and resample to match dest width */
312af69d88dSmrg         if (prevY != srcRow) {
313af69d88dSmrg            GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
314af69d88dSmrg
315af69d88dSmrg            switch (mode) {
316af69d88dSmrg            case DIRECT:
317af69d88dSmrg               memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
318af69d88dSmrg               break;
319af69d88dSmrg            case UNPACK_RGBA_FLOAT:
320af69d88dSmrg               _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
321af69d88dSmrg                                     srcBuffer);
322af69d88dSmrg               break;
323af69d88dSmrg            case UNPACK_Z_FLOAT:
324af69d88dSmrg               _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
325af69d88dSmrg                                        srcBuffer);
326af69d88dSmrg               break;
327af69d88dSmrg            case UNPACK_Z_INT:
328af69d88dSmrg               _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
329af69d88dSmrg                                       srcBuffer);
330af69d88dSmrg               break;
331af69d88dSmrg            case UNPACK_S:
332af69d88dSmrg               _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
333af69d88dSmrg                                              srcRowStart, srcBuffer);
334af69d88dSmrg               break;
335af69d88dSmrg            }
336af69d88dSmrg
3377ec681f3Smrg            resampleRow(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
338af69d88dSmrg            prevY = srcRow;
339af69d88dSmrg         }
3407117f1b4Smrg
341af69d88dSmrg         /* store pixel row in destination */
342af69d88dSmrg         switch (mode) {
343af69d88dSmrg         case DIRECT:
344af69d88dSmrg            memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
345af69d88dSmrg            break;
346af69d88dSmrg         case UNPACK_RGBA_FLOAT:
347af69d88dSmrg            _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
348af69d88dSmrg                                      dstRowStart);
349af69d88dSmrg            break;
350af69d88dSmrg         case UNPACK_Z_FLOAT:
351af69d88dSmrg            _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
352af69d88dSmrg                                   dstRowStart);
353af69d88dSmrg            break;
354af69d88dSmrg         case UNPACK_Z_INT:
355af69d88dSmrg            _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
356af69d88dSmrg                                  dstRowStart);
357af69d88dSmrg            break;
358af69d88dSmrg         case UNPACK_S:
359af69d88dSmrg            _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
360af69d88dSmrg                                         dstRowStart);
361af69d88dSmrg            break;
362af69d88dSmrg         }
3637117f1b4Smrg      }
3647117f1b4Smrg
365af69d88dSmrg      ctx->Driver.UnmapRenderbuffer(ctx, readRb);
366af69d88dSmrg      if (drawRb != readRb) {
367af69d88dSmrg         ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
368af69d88dSmrg      }
3697117f1b4Smrg   }
3707117f1b4Smrg
371af69d88dSmrgfail:
372cdc920a0Smrg   free(srcBuffer);
373cdc920a0Smrg   free(dstBuffer);
374af69d88dSmrg   return;
375af69d88dSmrg
376af69d88dSmrgfail_no_memory:
377af69d88dSmrg   free(srcBuffer);
378af69d88dSmrg   free(dstBuffer);
379af69d88dSmrg   _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
3807117f1b4Smrg}
3817117f1b4Smrg
3827117f1b4Smrg
3837117f1b4Smrg
3847117f1b4Smrg#define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
3857117f1b4Smrg
386af69d88dSmrgstatic inline GLfloat
3877117f1b4Smrglerp_2d(GLfloat a, GLfloat b,
3887117f1b4Smrg        GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
3897117f1b4Smrg{
3907117f1b4Smrg   const GLfloat temp0 = LERP(a, v00, v10);
3917117f1b4Smrg   const GLfloat temp1 = LERP(a, v01, v11);
3927117f1b4Smrg   return LERP(b, temp0, temp1);
3937117f1b4Smrg}
3947117f1b4Smrg
3957117f1b4Smrg
3967117f1b4Smrg/**
3977117f1b4Smrg * Bilinear interpolation of two source rows.
3987117f1b4Smrg * GLubyte pixels.
3997117f1b4Smrg */
4007117f1b4Smrgstatic void
4017117f1b4Smrgresample_linear_row_ub(GLint srcWidth, GLint dstWidth,
4027117f1b4Smrg                       const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
4037117f1b4Smrg                       GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
4047117f1b4Smrg{
4057117f1b4Smrg   const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
4067117f1b4Smrg   const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
4077117f1b4Smrg   GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
4087117f1b4Smrg   GLint dstCol;
4097117f1b4Smrg
4107117f1b4Smrg   for (dstCol = 0; dstCol < dstWidth; dstCol++) {
411af69d88dSmrg      const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
4127ec681f3Smrg      GLint srcCol0 = MAX2(0, util_ifloor(srcCol));
4137117f1b4Smrg      GLint srcCol1 = srcCol0 + 1;
4147117f1b4Smrg      GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
4157117f1b4Smrg      GLfloat red, green, blue, alpha;
4167117f1b4Smrg
41701e04c3fSmrg      assert(srcCol0 < srcWidth);
41801e04c3fSmrg      assert(srcCol1 <= srcWidth);
4197117f1b4Smrg
4207117f1b4Smrg      if (srcCol1 == srcWidth) {
4217117f1b4Smrg         /* last column fudge */
4227117f1b4Smrg         srcCol1--;
4237117f1b4Smrg         colWeight = 0.0;
4247117f1b4Smrg      }
4257117f1b4Smrg
4267117f1b4Smrg      if (flip) {
4277117f1b4Smrg         srcCol0 = srcWidth - 1 - srcCol0;
4287117f1b4Smrg         srcCol1 = srcWidth - 1 - srcCol1;
4297117f1b4Smrg      }
4307117f1b4Smrg
4317117f1b4Smrg      red = lerp_2d(colWeight, rowWeight,
4327117f1b4Smrg                    srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
4337117f1b4Smrg                    srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
4347117f1b4Smrg      green = lerp_2d(colWeight, rowWeight,
4357117f1b4Smrg                    srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
4367117f1b4Smrg                    srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
4377117f1b4Smrg      blue = lerp_2d(colWeight, rowWeight,
4387117f1b4Smrg                    srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
4397117f1b4Smrg                    srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
4407117f1b4Smrg      alpha = lerp_2d(colWeight, rowWeight,
4417117f1b4Smrg                    srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
4427117f1b4Smrg                    srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
4437ec681f3Smrg
4447ec681f3Smrg      dstColor[dstCol][RCOMP] = util_ifloor(red);
4457ec681f3Smrg      dstColor[dstCol][GCOMP] = util_ifloor(green);
4467ec681f3Smrg      dstColor[dstCol][BCOMP] = util_ifloor(blue);
4477ec681f3Smrg      dstColor[dstCol][ACOMP] = util_ifloor(alpha);
4487117f1b4Smrg   }
4497117f1b4Smrg}
4507117f1b4Smrg
4517117f1b4Smrg
452af69d88dSmrg/**
453af69d88dSmrg * Bilinear interpolation of two source rows.  floating point pixels.
454af69d88dSmrg */
455af69d88dSmrgstatic void
456af69d88dSmrgresample_linear_row_float(GLint srcWidth, GLint dstWidth,
457af69d88dSmrg                          const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
458af69d88dSmrg                          GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
459af69d88dSmrg{
460af69d88dSmrg   const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
461af69d88dSmrg   const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
462af69d88dSmrg   GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
463af69d88dSmrg   GLint dstCol;
464af69d88dSmrg
465af69d88dSmrg   for (dstCol = 0; dstCol < dstWidth; dstCol++) {
466af69d88dSmrg      const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
4677ec681f3Smrg      GLint srcCol0 = MAX2(0, util_ifloor(srcCol));
468af69d88dSmrg      GLint srcCol1 = srcCol0 + 1;
469af69d88dSmrg      GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
470af69d88dSmrg      GLfloat red, green, blue, alpha;
471af69d88dSmrg
47201e04c3fSmrg      assert(srcCol0 < srcWidth);
47301e04c3fSmrg      assert(srcCol1 <= srcWidth);
474af69d88dSmrg
475af69d88dSmrg      if (srcCol1 == srcWidth) {
476af69d88dSmrg         /* last column fudge */
477af69d88dSmrg         srcCol1--;
478af69d88dSmrg         colWeight = 0.0;
479af69d88dSmrg      }
480af69d88dSmrg
481af69d88dSmrg      if (flip) {
482af69d88dSmrg         srcCol0 = srcWidth - 1 - srcCol0;
483af69d88dSmrg         srcCol1 = srcWidth - 1 - srcCol1;
484af69d88dSmrg      }
485af69d88dSmrg
486af69d88dSmrg      red = lerp_2d(colWeight, rowWeight,
487af69d88dSmrg                    srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
488af69d88dSmrg                    srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
489af69d88dSmrg      green = lerp_2d(colWeight, rowWeight,
490af69d88dSmrg                    srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
491af69d88dSmrg                    srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
492af69d88dSmrg      blue = lerp_2d(colWeight, rowWeight,
493af69d88dSmrg                    srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
494af69d88dSmrg                    srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
495af69d88dSmrg      alpha = lerp_2d(colWeight, rowWeight,
496af69d88dSmrg                    srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
497af69d88dSmrg                    srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
4987ec681f3Smrg
499af69d88dSmrg      dstColor[dstCol][RCOMP] = red;
500af69d88dSmrg      dstColor[dstCol][GCOMP] = green;
501af69d88dSmrg      dstColor[dstCol][BCOMP] = blue;
502af69d88dSmrg      dstColor[dstCol][ACOMP] = alpha;
503af69d88dSmrg   }
504af69d88dSmrg}
505af69d88dSmrg
506af69d88dSmrg
5077117f1b4Smrg
5087117f1b4Smrg/**
509af69d88dSmrg * Bilinear filtered blit (color only, non-integer values).
5107117f1b4Smrg */
5117117f1b4Smrgstatic void
5123464ebd5Sriastradhblit_linear(struct gl_context *ctx,
51301e04c3fSmrg            struct gl_framebuffer *readFb,
51401e04c3fSmrg            struct gl_framebuffer *drawFb,
5157117f1b4Smrg            GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
5167117f1b4Smrg            GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
5177117f1b4Smrg{
518af69d88dSmrg   struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
519af69d88dSmrg   struct gl_renderbuffer_attachment *readAtt =
520af69d88dSmrg      &readFb->Attachment[readFb->_ColorReadBufferIndex];
5217117f1b4Smrg
5227117f1b4Smrg   const GLint srcWidth = ABS(srcX1 - srcX0);
5237117f1b4Smrg   const GLint dstWidth = ABS(dstX1 - dstX0);
5247117f1b4Smrg   const GLint srcHeight = ABS(srcY1 - srcY0);
5257117f1b4Smrg   const GLint dstHeight = ABS(dstY1 - dstY0);
5267117f1b4Smrg
5277117f1b4Smrg   const GLint srcXpos = MIN2(srcX0, srcX1);
5287117f1b4Smrg   const GLint srcYpos = MIN2(srcY0, srcY1);
5297117f1b4Smrg   const GLint dstXpos = MIN2(dstX0, dstX1);
5307117f1b4Smrg   const GLint dstYpos = MIN2(dstY0, dstY1);
5317117f1b4Smrg
5327117f1b4Smrg   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
5337117f1b4Smrg   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
5347117f1b4Smrg
5357117f1b4Smrg   GLint dstRow;
5367117f1b4Smrg
5377117f1b4Smrg   GLint pixelSize;
5387117f1b4Smrg   GLvoid *srcBuffer0, *srcBuffer1;
5397117f1b4Smrg   GLint srcBufferY0 = -1, srcBufferY1 = -1;
5407117f1b4Smrg   GLvoid *dstBuffer;
5417117f1b4Smrg
542af69d88dSmrg   mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
543af69d88dSmrg   GLuint bpp = _mesa_get_format_bytes(readFormat);
544af69d88dSmrg
545af69d88dSmrg   GLenum pixelType;
546af69d88dSmrg
547af69d88dSmrg   GLubyte *srcMap, *dstMap;
548af69d88dSmrg   GLint srcRowStride, dstRowStride;
549af69d88dSmrg   GLuint i;
550af69d88dSmrg
551af69d88dSmrg
552af69d88dSmrg   /* Determine datatype for resampling */
553af69d88dSmrg   if (_mesa_get_format_max_bits(readFormat) == 8 &&
554af69d88dSmrg       _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
555af69d88dSmrg      pixelType = GL_UNSIGNED_BYTE;
5567117f1b4Smrg      pixelSize = 4 * sizeof(GLubyte);
557af69d88dSmrg   }
558af69d88dSmrg   else {
559af69d88dSmrg      pixelType = GL_FLOAT;
5607117f1b4Smrg      pixelSize = 4 * sizeof(GLfloat);
5617117f1b4Smrg   }
5627117f1b4Smrg
5637117f1b4Smrg   /* Allocate the src/dst row buffers.
5647117f1b4Smrg    * Keep two adjacent src rows around for bilinear sampling.
5657117f1b4Smrg    */
566cdc920a0Smrg   srcBuffer0 = malloc(pixelSize * srcWidth);
567cdc920a0Smrg   srcBuffer1 = malloc(pixelSize * srcWidth);
568cdc920a0Smrg   dstBuffer = malloc(pixelSize * dstWidth);
569af69d88dSmrg   if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
570af69d88dSmrg      goto fail_no_memory;
5717117f1b4Smrg   }
5727117f1b4Smrg
573af69d88dSmrg   for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
57401e04c3fSmrg      gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i];
575af69d88dSmrg      struct gl_renderbuffer_attachment *drawAtt;
576af69d88dSmrg      struct gl_renderbuffer *drawRb;
577af69d88dSmrg      mesa_format drawFormat;
5787117f1b4Smrg
57901e04c3fSmrg      if (idx == BUFFER_NONE)
580af69d88dSmrg         continue;
5817117f1b4Smrg
582af69d88dSmrg      drawAtt = &drawFb->Attachment[idx];
583af69d88dSmrg      drawRb = drawAtt->Renderbuffer;
584af69d88dSmrg      if (!drawRb)
585af69d88dSmrg         continue;
5867117f1b4Smrg
587af69d88dSmrg      drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
5887117f1b4Smrg
589af69d88dSmrg      /*
590af69d88dSmrg       * Map src / dst renderbuffers
591af69d88dSmrg       */
592af69d88dSmrg      if ((readRb == drawRb) ||
593af69d88dSmrg          (readAtt->Texture && drawAtt->Texture &&
594af69d88dSmrg           (readAtt->Texture == drawAtt->Texture))) {
595af69d88dSmrg         /* map whole buffer for read/write */
596af69d88dSmrg         ctx->Driver.MapRenderbuffer(ctx, readRb,
597af69d88dSmrg                                     0, 0, readRb->Width, readRb->Height,
598af69d88dSmrg                                     GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
59901e04c3fSmrg                                     &srcMap, &srcRowStride,
60001e04c3fSmrg                                     readFb->FlipY);
601af69d88dSmrg         if (!srcMap) {
602af69d88dSmrg            goto fail_no_memory;
603af69d88dSmrg         }
6047117f1b4Smrg
605af69d88dSmrg         dstMap = srcMap;
606af69d88dSmrg         dstRowStride = srcRowStride;
6077117f1b4Smrg      }
6087117f1b4Smrg      else {
609af69d88dSmrg         /* different src/dst buffers */
610af69d88dSmrg         /* XXX with a bit of work we could just map the regions to be
611af69d88dSmrg          * read/written instead of the whole buffers.
612af69d88dSmrg          */
613af69d88dSmrg         ctx->Driver.MapRenderbuffer(ctx, readRb,
614af69d88dSmrg                                     0, 0, readRb->Width, readRb->Height,
61501e04c3fSmrg                                     GL_MAP_READ_BIT, &srcMap, &srcRowStride,
61601e04c3fSmrg                                     readFb->FlipY);
617af69d88dSmrg         if (!srcMap) {
618af69d88dSmrg            goto fail_no_memory;
619af69d88dSmrg         }
620af69d88dSmrg         ctx->Driver.MapRenderbuffer(ctx, drawRb,
621af69d88dSmrg                                     0, 0, drawRb->Width, drawRb->Height,
62201e04c3fSmrg                                     GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
62301e04c3fSmrg                                     drawFb->FlipY);
624af69d88dSmrg         if (!dstMap) {
625af69d88dSmrg            ctx->Driver.UnmapRenderbuffer(ctx, readRb);
626af69d88dSmrg            goto fail_no_memory;
627af69d88dSmrg         }
6287117f1b4Smrg      }
6297117f1b4Smrg
630af69d88dSmrg      for (dstRow = 0; dstRow < dstHeight; dstRow++) {
631af69d88dSmrg         const GLint dstY = dstYpos + dstRow;
632af69d88dSmrg         GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
6337ec681f3Smrg         GLint srcRow0 = MAX2(0, util_ifloor(srcRow));
634af69d88dSmrg         GLint srcRow1 = srcRow0 + 1;
635af69d88dSmrg         GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
636af69d88dSmrg
637af69d88dSmrg         if (srcRow1 == srcHeight) {
638af69d88dSmrg            /* last row fudge */
639af69d88dSmrg            srcRow1 = srcRow0;
640af69d88dSmrg            rowWeight = 0.0;
641af69d88dSmrg         }
6427117f1b4Smrg
643af69d88dSmrg         if (invertY) {
644af69d88dSmrg            srcRow0 = srcHeight - 1 - srcRow0;
645af69d88dSmrg            srcRow1 = srcHeight - 1 - srcRow1;
646af69d88dSmrg         }
6477117f1b4Smrg
648af69d88dSmrg         srcY0 = srcYpos + srcRow0;
649af69d88dSmrg         srcY1 = srcYpos + srcRow1;
6507117f1b4Smrg
651af69d88dSmrg         /* get the two source rows */
652af69d88dSmrg         if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
653af69d88dSmrg            /* use same source row buffers again */
654af69d88dSmrg         }
655af69d88dSmrg         else if (srcY0 == srcBufferY1) {
656af69d88dSmrg            /* move buffer1 into buffer0 by swapping pointers */
657af69d88dSmrg            GLvoid *tmp = srcBuffer0;
658af69d88dSmrg            srcBuffer0 = srcBuffer1;
659af69d88dSmrg            srcBuffer1 = tmp;
660af69d88dSmrg            /* get y1 row */
661af69d88dSmrg            {
662af69d88dSmrg               GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
663af69d88dSmrg               if (pixelType == GL_UNSIGNED_BYTE) {
664af69d88dSmrg                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
665af69d88dSmrg                                              src, srcBuffer1);
666af69d88dSmrg               }
667af69d88dSmrg               else {
668af69d88dSmrg                  _mesa_unpack_rgba_row(readFormat, srcWidth,
669af69d88dSmrg                                        src, srcBuffer1);
670af69d88dSmrg               }
671af69d88dSmrg            }
672af69d88dSmrg            srcBufferY0 = srcY0;
673af69d88dSmrg            srcBufferY1 = srcY1;
674af69d88dSmrg         }
675af69d88dSmrg         else {
676af69d88dSmrg            /* get both new rows */
677af69d88dSmrg            {
678af69d88dSmrg               GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
679af69d88dSmrg               GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
680af69d88dSmrg               if (pixelType == GL_UNSIGNED_BYTE) {
681af69d88dSmrg                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
682af69d88dSmrg                                              src0, srcBuffer0);
683af69d88dSmrg                  _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
684af69d88dSmrg                                              src1, srcBuffer1);
685af69d88dSmrg               }
686af69d88dSmrg               else {
687af69d88dSmrg                  _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
688af69d88dSmrg                  _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
689af69d88dSmrg               }
690af69d88dSmrg            }
691af69d88dSmrg            srcBufferY0 = srcY0;
692af69d88dSmrg            srcBufferY1 = srcY1;
693af69d88dSmrg         }
6947117f1b4Smrg
695af69d88dSmrg         if (pixelType == GL_UNSIGNED_BYTE) {
696af69d88dSmrg            resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
697af69d88dSmrg                                   dstBuffer, invertX, rowWeight);
698af69d88dSmrg         }
699af69d88dSmrg         else {
700af69d88dSmrg            resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
701af69d88dSmrg                                      dstBuffer, invertX, rowWeight);
702af69d88dSmrg         }
7037117f1b4Smrg
704af69d88dSmrg         /* store pixel row in destination */
705af69d88dSmrg         {
706af69d88dSmrg            GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
707af69d88dSmrg            if (pixelType == GL_UNSIGNED_BYTE) {
708af69d88dSmrg               _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
709af69d88dSmrg            }
710af69d88dSmrg            else {
711af69d88dSmrg               _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
712af69d88dSmrg            }
713af69d88dSmrg         }
714af69d88dSmrg      }
7157117f1b4Smrg
716af69d88dSmrg      ctx->Driver.UnmapRenderbuffer(ctx, readRb);
717af69d88dSmrg      if (drawRb != readRb) {
718af69d88dSmrg         ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
719af69d88dSmrg      }
7207117f1b4Smrg   }
7217117f1b4Smrg
722af69d88dSmrg   free(srcBuffer0);
723af69d88dSmrg   free(srcBuffer1);
724af69d88dSmrg   free(dstBuffer);
725af69d88dSmrg   return;
7267117f1b4Smrg
727af69d88dSmrgfail_no_memory:
728af69d88dSmrg   free(srcBuffer0);
729af69d88dSmrg   free(srcBuffer1);
730af69d88dSmrg   free(dstBuffer);
731af69d88dSmrg   _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
7327117f1b4Smrg}
7337117f1b4Smrg
7347117f1b4Smrg
735af69d88dSmrg
7367117f1b4Smrg/**
7377117f1b4Smrg * Software fallback for glBlitFramebufferEXT().
7387117f1b4Smrg */
7397117f1b4Smrgvoid
7403464ebd5Sriastradh_swrast_BlitFramebuffer(struct gl_context *ctx,
74101e04c3fSmrg                        struct gl_framebuffer *readFb,
74201e04c3fSmrg                        struct gl_framebuffer *drawFb,
7437117f1b4Smrg                        GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
7447117f1b4Smrg                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
7457117f1b4Smrg                        GLbitfield mask, GLenum filter)
7467117f1b4Smrg{
7474a49301eSmrg   static const GLbitfield buffers[3] = {
7487117f1b4Smrg      GL_COLOR_BUFFER_BIT,
7497117f1b4Smrg      GL_DEPTH_BUFFER_BIT,
7507117f1b4Smrg      GL_STENCIL_BUFFER_BIT
7517117f1b4Smrg   };
752af69d88dSmrg   static const GLenum buffer_enums[3] = {
753af69d88dSmrg      GL_COLOR,
754af69d88dSmrg      GL_DEPTH,
755af69d88dSmrg      GL_STENCIL,
756af69d88dSmrg   };
7577117f1b4Smrg   GLint i;
7587117f1b4Smrg
759af69d88dSmrg   /* Page 679 of OpenGL 4.4 spec says:
760af69d88dSmrg    *    "Added BlitFramebuffer to commands affected by conditional rendering in
761af69d88dSmrg    *     section 10.10 (Bug 9562)."
762af69d88dSmrg    */
763af69d88dSmrg   if (!_mesa_check_conditional_render(ctx))
764af69d88dSmrg      return; /* Do not blit */
765af69d88dSmrg
76601e04c3fSmrg   if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1,
7674a49301eSmrg                        &dstX0, &dstY0, &dstX1, &dstY1)) {
7687117f1b4Smrg      return;
7697117f1b4Smrg   }
7707117f1b4Smrg
771af69d88dSmrg   if (SWRAST_CONTEXT(ctx)->NewState)
772af69d88dSmrg      _swrast_validate_derived(ctx);
7737117f1b4Smrg
774af69d88dSmrg   /* First, try covering whatever buffers possible using the fast 1:1 copy
775af69d88dSmrg    * path.
776af69d88dSmrg    */
7777117f1b4Smrg   if (srcX1 - srcX0 == dstX1 - dstX0 &&
7787117f1b4Smrg       srcY1 - srcY0 == dstY1 - dstY0 &&
7797117f1b4Smrg       srcX0 < srcX1 &&
7807117f1b4Smrg       srcY0 < srcY1 &&
7817117f1b4Smrg       dstX0 < dstX1 &&
7827117f1b4Smrg       dstY0 < dstY1) {
7837117f1b4Smrg      for (i = 0; i < 3; i++) {
7847117f1b4Smrg         if (mask & buffers[i]) {
78501e04c3fSmrg            if (swrast_fast_copy_pixels(ctx,
78601e04c3fSmrg                                        readFb, drawFb,
78701e04c3fSmrg                                        srcX0, srcY0,
78801e04c3fSmrg                                        srcX1 - srcX0, srcY1 - srcY0,
78901e04c3fSmrg                                        dstX0, dstY0,
79001e04c3fSmrg                                        buffer_enums[i])) {
79101e04c3fSmrg               mask &= ~buffers[i];
79201e04c3fSmrg            }
79301e04c3fSmrg         }
7947117f1b4Smrg      }
795af69d88dSmrg
796af69d88dSmrg      if (!mask)
79701e04c3fSmrg         return;
7987117f1b4Smrg   }
799af69d88dSmrg
800af69d88dSmrg   if (filter == GL_NEAREST) {
801af69d88dSmrg      for (i = 0; i < 3; i++) {
80201e04c3fSmrg          if (mask & buffers[i]) {
80301e04c3fSmrg             blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
80401e04c3fSmrg                          dstX0, dstY0, dstX1, dstY1, buffers[i]);
80501e04c3fSmrg          }
8067117f1b4Smrg      }
807af69d88dSmrg   }
808af69d88dSmrg   else {
80901e04c3fSmrg      assert(filter == GL_LINEAR);
810af69d88dSmrg      if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
81101e04c3fSmrg         blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
81201e04c3fSmrg                     dstX0, dstY0, dstX1, dstY1);
8137117f1b4Smrg      }
8147117f1b4Smrg   }
8157117f1b4Smrg
8167117f1b4Smrg}
817