Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5563 | serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 1999-2006 Brian Paul 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 "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included |
||
14 | * in all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
22 | * OTHER DEALINGS IN THE SOFTWARE. |
||
23 | */ |
||
24 | |||
25 | |||
26 | #include "main/glheader.h" |
||
27 | #include "main/condrender.h" |
||
28 | #include "main/image.h" |
||
29 | #include "main/macros.h" |
||
30 | #include "main/format_unpack.h" |
||
31 | #include "main/format_pack.h" |
||
32 | #include "s_context.h" |
||
33 | |||
34 | |||
35 | #define ABS(X) ((X) < 0 ? -(X) : (X)) |
||
36 | |||
37 | |||
38 | /** |
||
39 | * Generate a row resampler function for GL_NEAREST mode. |
||
40 | */ |
||
41 | #define RESAMPLE(NAME, PIXELTYPE, SIZE) \ |
||
42 | static void \ |
||
43 | NAME(GLint srcWidth, GLint dstWidth, \ |
||
44 | const GLvoid *srcBuffer, GLvoid *dstBuffer, \ |
||
45 | GLboolean flip) \ |
||
46 | { \ |
||
47 | const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\ |
||
48 | PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \ |
||
49 | GLint dstCol; \ |
||
50 | \ |
||
51 | if (flip) { \ |
||
52 | for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ |
||
53 | GLint srcCol = (dstCol * srcWidth) / dstWidth; \ |
||
54 | ASSERT(srcCol >= 0); \ |
||
55 | ASSERT(srcCol < srcWidth); \ |
||
56 | srcCol = srcWidth - 1 - srcCol; /* flip */ \ |
||
57 | if (SIZE == 1) { \ |
||
58 | dst[dstCol] = src[srcCol]; \ |
||
59 | } \ |
||
60 | else if (SIZE == 2) { \ |
||
61 | dst[dstCol*2+0] = src[srcCol*2+0]; \ |
||
62 | dst[dstCol*2+1] = src[srcCol*2+1]; \ |
||
63 | } \ |
||
64 | else if (SIZE == 4) { \ |
||
65 | dst[dstCol*4+0] = src[srcCol*4+0]; \ |
||
66 | dst[dstCol*4+1] = src[srcCol*4+1]; \ |
||
67 | dst[dstCol*4+2] = src[srcCol*4+2]; \ |
||
68 | dst[dstCol*4+3] = src[srcCol*4+3]; \ |
||
69 | } \ |
||
70 | } \ |
||
71 | } \ |
||
72 | else { \ |
||
73 | for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ |
||
74 | GLint srcCol = (dstCol * srcWidth) / dstWidth; \ |
||
75 | ASSERT(srcCol >= 0); \ |
||
76 | ASSERT(srcCol < srcWidth); \ |
||
77 | if (SIZE == 1) { \ |
||
78 | dst[dstCol] = src[srcCol]; \ |
||
79 | } \ |
||
80 | else if (SIZE == 2) { \ |
||
81 | dst[dstCol*2+0] = src[srcCol*2+0]; \ |
||
82 | dst[dstCol*2+1] = src[srcCol*2+1]; \ |
||
83 | } \ |
||
84 | else if (SIZE == 4) { \ |
||
85 | dst[dstCol*4+0] = src[srcCol*4+0]; \ |
||
86 | dst[dstCol*4+1] = src[srcCol*4+1]; \ |
||
87 | dst[dstCol*4+2] = src[srcCol*4+2]; \ |
||
88 | dst[dstCol*4+3] = src[srcCol*4+3]; \ |
||
89 | } \ |
||
90 | } \ |
||
91 | } \ |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * Resamplers for 1, 2, 4, 8 and 16-byte pixels. |
||
96 | */ |
||
97 | RESAMPLE(resample_row_1, GLubyte, 1) |
||
98 | RESAMPLE(resample_row_2, GLushort, 1) |
||
99 | RESAMPLE(resample_row_4, GLuint, 1) |
||
100 | RESAMPLE(resample_row_8, GLuint, 2) |
||
101 | RESAMPLE(resample_row_16, GLuint, 4) |
||
102 | |||
103 | |||
104 | /** |
||
105 | * Blit color, depth or stencil with GL_NEAREST filtering. |
||
106 | */ |
||
107 | static void |
||
108 | blit_nearest(struct gl_context *ctx, |
||
109 | GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
110 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, |
||
111 | GLbitfield buffer) |
||
112 | { |
||
113 | struct gl_renderbuffer *readRb, *drawRb = NULL; |
||
114 | struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL; |
||
115 | struct gl_framebuffer *readFb = ctx->ReadBuffer; |
||
116 | struct gl_framebuffer *drawFb = ctx->DrawBuffer; |
||
117 | GLuint numDrawBuffers = 0; |
||
118 | GLuint i; |
||
119 | |||
120 | const GLint srcWidth = ABS(srcX1 - srcX0); |
||
121 | const GLint dstWidth = ABS(dstX1 - dstX0); |
||
122 | const GLint srcHeight = ABS(srcY1 - srcY0); |
||
123 | const GLint dstHeight = ABS(dstY1 - dstY0); |
||
124 | |||
125 | const GLint srcXpos = MIN2(srcX0, srcX1); |
||
126 | const GLint srcYpos = MIN2(srcY0, srcY1); |
||
127 | const GLint dstXpos = MIN2(dstX0, dstX1); |
||
128 | const GLint dstYpos = MIN2(dstY0, dstY1); |
||
129 | |||
130 | const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); |
||
131 | const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); |
||
132 | enum mode { |
||
133 | DIRECT, |
||
134 | UNPACK_RGBA_FLOAT, |
||
135 | UNPACK_Z_FLOAT, |
||
136 | UNPACK_Z_INT, |
||
137 | UNPACK_S, |
||
138 | } mode = DIRECT; |
||
139 | GLubyte *srcMap, *dstMap; |
||
140 | GLint srcRowStride, dstRowStride; |
||
141 | GLint dstRow; |
||
142 | |||
143 | GLint pixelSize = 0; |
||
144 | GLvoid *srcBuffer, *dstBuffer; |
||
145 | GLint prevY = -1; |
||
146 | |||
147 | typedef void (*resample_func)(GLint srcWidth, GLint dstWidth, |
||
148 | const GLvoid *srcBuffer, GLvoid *dstBuffer, |
||
149 | GLboolean flip); |
||
150 | resample_func resampleRow; |
||
151 | |||
152 | switch (buffer) { |
||
153 | case GL_COLOR_BUFFER_BIT: |
||
154 | readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex]; |
||
155 | readRb = readFb->_ColorReadBuffer; |
||
156 | numDrawBuffers = drawFb->_NumColorDrawBuffers; |
||
157 | break; |
||
158 | case GL_DEPTH_BUFFER_BIT: |
||
159 | readAtt = &readFb->Attachment[BUFFER_DEPTH]; |
||
160 | drawAtt = &drawFb->Attachment[BUFFER_DEPTH]; |
||
161 | readRb = readAtt->Renderbuffer; |
||
162 | drawRb = drawAtt->Renderbuffer; |
||
163 | numDrawBuffers = 1; |
||
164 | |||
165 | /* Note that for depth/stencil, the formats of src/dst must match. By |
||
166 | * using the core helpers for pack/unpack, we avoid needing to handle |
||
167 | * masking for things like DEPTH copies of Z24S8. |
||
168 | */ |
||
169 | if (readRb->Format == MESA_FORMAT_Z32_FLOAT || |
||
170 | readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) { |
||
171 | mode = UNPACK_Z_FLOAT; |
||
172 | } else { |
||
173 | mode = UNPACK_Z_INT; |
||
174 | } |
||
175 | pixelSize = 4; |
||
176 | break; |
||
177 | case GL_STENCIL_BUFFER_BIT: |
||
178 | readAtt = &readFb->Attachment[BUFFER_STENCIL]; |
||
179 | drawAtt = &drawFb->Attachment[BUFFER_STENCIL]; |
||
180 | readRb = readAtt->Renderbuffer; |
||
181 | drawRb = drawAtt->Renderbuffer; |
||
182 | numDrawBuffers = 1; |
||
183 | mode = UNPACK_S; |
||
184 | pixelSize = 1; |
||
185 | break; |
||
186 | default: |
||
187 | _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); |
||
188 | return; |
||
189 | } |
||
190 | |||
191 | /* allocate the src/dst row buffers */ |
||
192 | srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth); |
||
193 | dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth); |
||
194 | if (!srcBuffer || !dstBuffer) |
||
195 | goto fail_no_memory; |
||
196 | |||
197 | /* Blit to all the draw buffers */ |
||
198 | for (i = 0; i < numDrawBuffers; i++) { |
||
199 | if (buffer == GL_COLOR_BUFFER_BIT) { |
||
200 | int idx = drawFb->_ColorDrawBufferIndexes[i]; |
||
201 | if (idx == -1) |
||
202 | continue; |
||
203 | drawAtt = &drawFb->Attachment[idx]; |
||
204 | drawRb = drawAtt->Renderbuffer; |
||
205 | |||
206 | if (!drawRb) |
||
207 | continue; |
||
208 | |||
209 | if (readRb->Format == drawRb->Format) { |
||
210 | mode = DIRECT; |
||
211 | pixelSize = _mesa_get_format_bytes(readRb->Format); |
||
212 | } else { |
||
213 | mode = UNPACK_RGBA_FLOAT; |
||
214 | pixelSize = 16; |
||
215 | } |
||
216 | } |
||
217 | |||
218 | /* choose row resampler */ |
||
219 | switch (pixelSize) { |
||
220 | case 1: |
||
221 | resampleRow = resample_row_1; |
||
222 | break; |
||
223 | case 2: |
||
224 | resampleRow = resample_row_2; |
||
225 | break; |
||
226 | case 4: |
||
227 | resampleRow = resample_row_4; |
||
228 | break; |
||
229 | case 8: |
||
230 | resampleRow = resample_row_8; |
||
231 | break; |
||
232 | case 16: |
||
233 | resampleRow = resample_row_16; |
||
234 | break; |
||
235 | default: |
||
236 | _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", |
||
237 | pixelSize); |
||
238 | goto fail; |
||
239 | } |
||
240 | |||
241 | if ((readRb == drawRb) || |
||
242 | (readAtt->Texture && drawAtt->Texture && |
||
243 | (readAtt->Texture == drawAtt->Texture))) { |
||
244 | /* map whole buffer for read/write */ |
||
245 | /* XXX we could be clever and just map the union region of the |
||
246 | * source and dest rects. |
||
247 | */ |
||
248 | GLubyte *map; |
||
249 | GLint rowStride; |
||
250 | GLint formatSize = _mesa_get_format_bytes(readRb->Format); |
||
251 | |||
252 | ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, |
||
253 | readRb->Width, readRb->Height, |
||
254 | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, |
||
255 | &map, &rowStride); |
||
256 | if (!map) { |
||
257 | goto fail_no_memory; |
||
258 | } |
||
259 | |||
260 | srcMap = map + srcYpos * rowStride + srcXpos * formatSize; |
||
261 | dstMap = map + dstYpos * rowStride + dstXpos * formatSize; |
||
262 | |||
263 | /* this handles overlapping copies */ |
||
264 | if (srcY0 < dstY0) { |
||
265 | /* copy in reverse (top->down) order */ |
||
266 | srcMap += rowStride * (readRb->Height - 1); |
||
267 | dstMap += rowStride * (readRb->Height - 1); |
||
268 | srcRowStride = -rowStride; |
||
269 | dstRowStride = -rowStride; |
||
270 | } |
||
271 | else { |
||
272 | /* copy in normal (bottom->up) order */ |
||
273 | srcRowStride = rowStride; |
||
274 | dstRowStride = rowStride; |
||
275 | } |
||
276 | } |
||
277 | else { |
||
278 | /* different src/dst buffers */ |
||
279 | ctx->Driver.MapRenderbuffer(ctx, readRb, |
||
280 | srcXpos, srcYpos, |
||
281 | srcWidth, srcHeight, |
||
282 | GL_MAP_READ_BIT, &srcMap, &srcRowStride); |
||
283 | if (!srcMap) { |
||
284 | goto fail_no_memory; |
||
285 | } |
||
286 | ctx->Driver.MapRenderbuffer(ctx, drawRb, |
||
287 | dstXpos, dstYpos, |
||
288 | dstWidth, dstHeight, |
||
289 | GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); |
||
290 | if (!dstMap) { |
||
291 | ctx->Driver.UnmapRenderbuffer(ctx, readRb); |
||
292 | goto fail_no_memory; |
||
293 | } |
||
294 | } |
||
295 | |||
296 | for (dstRow = 0; dstRow < dstHeight; dstRow++) { |
||
297 | GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; |
||
298 | GLint srcRow = IROUND(srcRowF); |
||
299 | GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; |
||
300 | |||
301 | ASSERT(srcRow >= 0); |
||
302 | ASSERT(srcRow < srcHeight); |
||
303 | |||
304 | if (invertY) { |
||
305 | srcRow = srcHeight - 1 - srcRow; |
||
306 | } |
||
307 | |||
308 | /* get pixel row from source and resample to match dest width */ |
||
309 | if (prevY != srcRow) { |
||
310 | GLubyte *srcRowStart = srcMap + srcRowStride * srcRow; |
||
311 | |||
312 | switch (mode) { |
||
313 | case DIRECT: |
||
314 | memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth); |
||
315 | break; |
||
316 | case UNPACK_RGBA_FLOAT: |
||
317 | _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart, |
||
318 | srcBuffer); |
||
319 | break; |
||
320 | case UNPACK_Z_FLOAT: |
||
321 | _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart, |
||
322 | srcBuffer); |
||
323 | break; |
||
324 | case UNPACK_Z_INT: |
||
325 | _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart, |
||
326 | srcBuffer); |
||
327 | break; |
||
328 | case UNPACK_S: |
||
329 | _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth, |
||
330 | srcRowStart, srcBuffer); |
||
331 | break; |
||
332 | } |
||
333 | |||
334 | (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); |
||
335 | prevY = srcRow; |
||
336 | } |
||
337 | |||
338 | /* store pixel row in destination */ |
||
339 | switch (mode) { |
||
340 | case DIRECT: |
||
341 | memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth); |
||
342 | break; |
||
343 | case UNPACK_RGBA_FLOAT: |
||
344 | _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer, |
||
345 | dstRowStart); |
||
346 | break; |
||
347 | case UNPACK_Z_FLOAT: |
||
348 | _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer, |
||
349 | dstRowStart); |
||
350 | break; |
||
351 | case UNPACK_Z_INT: |
||
352 | _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer, |
||
353 | dstRowStart); |
||
354 | break; |
||
355 | case UNPACK_S: |
||
356 | _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer, |
||
357 | dstRowStart); |
||
358 | break; |
||
359 | } |
||
360 | } |
||
361 | |||
362 | ctx->Driver.UnmapRenderbuffer(ctx, readRb); |
||
363 | if (drawRb != readRb) { |
||
364 | ctx->Driver.UnmapRenderbuffer(ctx, drawRb); |
||
365 | } |
||
366 | } |
||
367 | |||
368 | fail: |
||
369 | free(srcBuffer); |
||
370 | free(dstBuffer); |
||
371 | return; |
||
372 | |||
373 | fail_no_memory: |
||
374 | free(srcBuffer); |
||
375 | free(dstBuffer); |
||
376 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer"); |
||
377 | } |
||
378 | |||
379 | |||
380 | |||
381 | #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) |
||
382 | |||
383 | static inline GLfloat |
||
384 | lerp_2d(GLfloat a, GLfloat b, |
||
385 | GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) |
||
386 | { |
||
387 | const GLfloat temp0 = LERP(a, v00, v10); |
||
388 | const GLfloat temp1 = LERP(a, v01, v11); |
||
389 | return LERP(b, temp0, temp1); |
||
390 | } |
||
391 | |||
392 | |||
393 | /** |
||
394 | * Bilinear interpolation of two source rows. |
||
395 | * GLubyte pixels. |
||
396 | */ |
||
397 | static void |
||
398 | resample_linear_row_ub(GLint srcWidth, GLint dstWidth, |
||
399 | const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, |
||
400 | GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) |
||
401 | { |
||
402 | const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; |
||
403 | const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; |
||
404 | GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; |
||
405 | GLint dstCol; |
||
406 | |||
407 | for (dstCol = 0; dstCol < dstWidth; dstCol++) { |
||
408 | const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; |
||
409 | GLint srcCol0 = MAX2(0, IFLOOR(srcCol)); |
||
410 | GLint srcCol1 = srcCol0 + 1; |
||
411 | GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ |
||
412 | GLfloat red, green, blue, alpha; |
||
413 | |||
414 | ASSERT(srcCol0 < srcWidth); |
||
415 | ASSERT(srcCol1 <= srcWidth); |
||
416 | |||
417 | if (srcCol1 == srcWidth) { |
||
418 | /* last column fudge */ |
||
419 | srcCol1--; |
||
420 | colWeight = 0.0; |
||
421 | } |
||
422 | |||
423 | if (flip) { |
||
424 | srcCol0 = srcWidth - 1 - srcCol0; |
||
425 | srcCol1 = srcWidth - 1 - srcCol1; |
||
426 | } |
||
427 | |||
428 | red = lerp_2d(colWeight, rowWeight, |
||
429 | srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], |
||
430 | srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); |
||
431 | green = lerp_2d(colWeight, rowWeight, |
||
432 | srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], |
||
433 | srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); |
||
434 | blue = lerp_2d(colWeight, rowWeight, |
||
435 | srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], |
||
436 | srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); |
||
437 | alpha = lerp_2d(colWeight, rowWeight, |
||
438 | srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], |
||
439 | srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); |
||
440 | |||
441 | dstColor[dstCol][RCOMP] = IFLOOR(red); |
||
442 | dstColor[dstCol][GCOMP] = IFLOOR(green); |
||
443 | dstColor[dstCol][BCOMP] = IFLOOR(blue); |
||
444 | dstColor[dstCol][ACOMP] = IFLOOR(alpha); |
||
445 | } |
||
446 | } |
||
447 | |||
448 | |||
449 | /** |
||
450 | * Bilinear interpolation of two source rows. floating point pixels. |
||
451 | */ |
||
452 | static void |
||
453 | resample_linear_row_float(GLint srcWidth, GLint dstWidth, |
||
454 | const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, |
||
455 | GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) |
||
456 | { |
||
457 | const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0; |
||
458 | const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1; |
||
459 | GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer; |
||
460 | GLint dstCol; |
||
461 | |||
462 | for (dstCol = 0; dstCol < dstWidth; dstCol++) { |
||
463 | const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; |
||
464 | GLint srcCol0 = MAX2(0, IFLOOR(srcCol)); |
||
465 | GLint srcCol1 = srcCol0 + 1; |
||
466 | GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ |
||
467 | GLfloat red, green, blue, alpha; |
||
468 | |||
469 | ASSERT(srcCol0 < srcWidth); |
||
470 | ASSERT(srcCol1 <= srcWidth); |
||
471 | |||
472 | if (srcCol1 == srcWidth) { |
||
473 | /* last column fudge */ |
||
474 | srcCol1--; |
||
475 | colWeight = 0.0; |
||
476 | } |
||
477 | |||
478 | if (flip) { |
||
479 | srcCol0 = srcWidth - 1 - srcCol0; |
||
480 | srcCol1 = srcWidth - 1 - srcCol1; |
||
481 | } |
||
482 | |||
483 | red = lerp_2d(colWeight, rowWeight, |
||
484 | srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], |
||
485 | srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); |
||
486 | green = lerp_2d(colWeight, rowWeight, |
||
487 | srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], |
||
488 | srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); |
||
489 | blue = lerp_2d(colWeight, rowWeight, |
||
490 | srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], |
||
491 | srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); |
||
492 | alpha = lerp_2d(colWeight, rowWeight, |
||
493 | srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], |
||
494 | srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); |
||
495 | |||
496 | dstColor[dstCol][RCOMP] = red; |
||
497 | dstColor[dstCol][GCOMP] = green; |
||
498 | dstColor[dstCol][BCOMP] = blue; |
||
499 | dstColor[dstCol][ACOMP] = alpha; |
||
500 | } |
||
501 | } |
||
502 | |||
503 | |||
504 | |||
505 | /** |
||
506 | * Bilinear filtered blit (color only, non-integer values). |
||
507 | */ |
||
508 | static void |
||
509 | blit_linear(struct gl_context *ctx, |
||
510 | GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
511 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) |
||
512 | { |
||
513 | struct gl_framebuffer *drawFb = ctx->DrawBuffer; |
||
514 | struct gl_framebuffer *readFb = ctx->ReadBuffer; |
||
515 | struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer; |
||
516 | struct gl_renderbuffer_attachment *readAtt = |
||
517 | &readFb->Attachment[readFb->_ColorReadBufferIndex]; |
||
518 | |||
519 | const GLint srcWidth = ABS(srcX1 - srcX0); |
||
520 | const GLint dstWidth = ABS(dstX1 - dstX0); |
||
521 | const GLint srcHeight = ABS(srcY1 - srcY0); |
||
522 | const GLint dstHeight = ABS(dstY1 - dstY0); |
||
523 | |||
524 | const GLint srcXpos = MIN2(srcX0, srcX1); |
||
525 | const GLint srcYpos = MIN2(srcY0, srcY1); |
||
526 | const GLint dstXpos = MIN2(dstX0, dstX1); |
||
527 | const GLint dstYpos = MIN2(dstY0, dstY1); |
||
528 | |||
529 | const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); |
||
530 | const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); |
||
531 | |||
532 | GLint dstRow; |
||
533 | |||
534 | GLint pixelSize; |
||
535 | GLvoid *srcBuffer0, *srcBuffer1; |
||
536 | GLint srcBufferY0 = -1, srcBufferY1 = -1; |
||
537 | GLvoid *dstBuffer; |
||
538 | |||
539 | gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); |
||
540 | GLuint bpp = _mesa_get_format_bytes(readFormat); |
||
541 | |||
542 | GLenum pixelType; |
||
543 | |||
544 | GLubyte *srcMap, *dstMap; |
||
545 | GLint srcRowStride, dstRowStride; |
||
546 | GLuint i; |
||
547 | |||
548 | |||
549 | /* Determine datatype for resampling */ |
||
550 | if (_mesa_get_format_max_bits(readFormat) == 8 && |
||
551 | _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { |
||
552 | pixelType = GL_UNSIGNED_BYTE; |
||
553 | pixelSize = 4 * sizeof(GLubyte); |
||
554 | } |
||
555 | else { |
||
556 | pixelType = GL_FLOAT; |
||
557 | pixelSize = 4 * sizeof(GLfloat); |
||
558 | } |
||
559 | |||
560 | /* Allocate the src/dst row buffers. |
||
561 | * Keep two adjacent src rows around for bilinear sampling. |
||
562 | */ |
||
563 | srcBuffer0 = malloc(pixelSize * srcWidth); |
||
564 | srcBuffer1 = malloc(pixelSize * srcWidth); |
||
565 | dstBuffer = malloc(pixelSize * dstWidth); |
||
566 | if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) { |
||
567 | goto fail_no_memory; |
||
568 | } |
||
569 | |||
570 | for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { |
||
571 | GLint idx = drawFb->_ColorDrawBufferIndexes[i]; |
||
572 | struct gl_renderbuffer_attachment *drawAtt; |
||
573 | struct gl_renderbuffer *drawRb; |
||
574 | gl_format drawFormat; |
||
575 | |||
576 | if (idx == -1) |
||
577 | continue; |
||
578 | |||
579 | drawAtt = &drawFb->Attachment[idx]; |
||
580 | drawRb = drawAtt->Renderbuffer; |
||
581 | if (!drawRb) |
||
582 | continue; |
||
583 | |||
584 | drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); |
||
585 | |||
586 | /* |
||
587 | * Map src / dst renderbuffers |
||
588 | */ |
||
589 | if ((readRb == drawRb) || |
||
590 | (readAtt->Texture && drawAtt->Texture && |
||
591 | (readAtt->Texture == drawAtt->Texture))) { |
||
592 | /* map whole buffer for read/write */ |
||
593 | ctx->Driver.MapRenderbuffer(ctx, readRb, |
||
594 | 0, 0, readRb->Width, readRb->Height, |
||
595 | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, |
||
596 | &srcMap, &srcRowStride); |
||
597 | if (!srcMap) { |
||
598 | goto fail_no_memory; |
||
599 | } |
||
600 | |||
601 | dstMap = srcMap; |
||
602 | dstRowStride = srcRowStride; |
||
603 | } |
||
604 | else { |
||
605 | /* different src/dst buffers */ |
||
606 | /* XXX with a bit of work we could just map the regions to be |
||
607 | * read/written instead of the whole buffers. |
||
608 | */ |
||
609 | ctx->Driver.MapRenderbuffer(ctx, readRb, |
||
610 | 0, 0, readRb->Width, readRb->Height, |
||
611 | GL_MAP_READ_BIT, &srcMap, &srcRowStride); |
||
612 | if (!srcMap) { |
||
613 | goto fail_no_memory; |
||
614 | } |
||
615 | ctx->Driver.MapRenderbuffer(ctx, drawRb, |
||
616 | 0, 0, drawRb->Width, drawRb->Height, |
||
617 | GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); |
||
618 | if (!dstMap) { |
||
619 | ctx->Driver.UnmapRenderbuffer(ctx, readRb); |
||
620 | goto fail_no_memory; |
||
621 | } |
||
622 | } |
||
623 | |||
624 | for (dstRow = 0; dstRow < dstHeight; dstRow++) { |
||
625 | const GLint dstY = dstYpos + dstRow; |
||
626 | GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; |
||
627 | GLint srcRow0 = MAX2(0, IFLOOR(srcRow)); |
||
628 | GLint srcRow1 = srcRow0 + 1; |
||
629 | GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ |
||
630 | |||
631 | if (srcRow1 == srcHeight) { |
||
632 | /* last row fudge */ |
||
633 | srcRow1 = srcRow0; |
||
634 | rowWeight = 0.0; |
||
635 | } |
||
636 | |||
637 | if (invertY) { |
||
638 | srcRow0 = srcHeight - 1 - srcRow0; |
||
639 | srcRow1 = srcHeight - 1 - srcRow1; |
||
640 | } |
||
641 | |||
642 | srcY0 = srcYpos + srcRow0; |
||
643 | srcY1 = srcYpos + srcRow1; |
||
644 | |||
645 | /* get the two source rows */ |
||
646 | if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { |
||
647 | /* use same source row buffers again */ |
||
648 | } |
||
649 | else if (srcY0 == srcBufferY1) { |
||
650 | /* move buffer1 into buffer0 by swapping pointers */ |
||
651 | GLvoid *tmp = srcBuffer0; |
||
652 | srcBuffer0 = srcBuffer1; |
||
653 | srcBuffer1 = tmp; |
||
654 | /* get y1 row */ |
||
655 | { |
||
656 | GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; |
||
657 | if (pixelType == GL_UNSIGNED_BYTE) { |
||
658 | _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, |
||
659 | src, srcBuffer1); |
||
660 | } |
||
661 | else { |
||
662 | _mesa_unpack_rgba_row(readFormat, srcWidth, |
||
663 | src, srcBuffer1); |
||
664 | } |
||
665 | } |
||
666 | srcBufferY0 = srcY0; |
||
667 | srcBufferY1 = srcY1; |
||
668 | } |
||
669 | else { |
||
670 | /* get both new rows */ |
||
671 | { |
||
672 | GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; |
||
673 | GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; |
||
674 | if (pixelType == GL_UNSIGNED_BYTE) { |
||
675 | _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, |
||
676 | src0, srcBuffer0); |
||
677 | _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, |
||
678 | src1, srcBuffer1); |
||
679 | } |
||
680 | else { |
||
681 | _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); |
||
682 | _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); |
||
683 | } |
||
684 | } |
||
685 | srcBufferY0 = srcY0; |
||
686 | srcBufferY1 = srcY1; |
||
687 | } |
||
688 | |||
689 | if (pixelType == GL_UNSIGNED_BYTE) { |
||
690 | resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, |
||
691 | dstBuffer, invertX, rowWeight); |
||
692 | } |
||
693 | else { |
||
694 | resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, |
||
695 | dstBuffer, invertX, rowWeight); |
||
696 | } |
||
697 | |||
698 | /* store pixel row in destination */ |
||
699 | { |
||
700 | GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; |
||
701 | if (pixelType == GL_UNSIGNED_BYTE) { |
||
702 | _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); |
||
703 | } |
||
704 | else { |
||
705 | _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); |
||
706 | } |
||
707 | } |
||
708 | } |
||
709 | |||
710 | ctx->Driver.UnmapRenderbuffer(ctx, readRb); |
||
711 | if (drawRb != readRb) { |
||
712 | ctx->Driver.UnmapRenderbuffer(ctx, drawRb); |
||
713 | } |
||
714 | } |
||
715 | |||
716 | free(srcBuffer0); |
||
717 | free(srcBuffer1); |
||
718 | free(dstBuffer); |
||
719 | return; |
||
720 | |||
721 | fail_no_memory: |
||
722 | free(srcBuffer0); |
||
723 | free(srcBuffer1); |
||
724 | free(dstBuffer); |
||
725 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); |
||
726 | } |
||
727 | |||
728 | |||
729 | |||
730 | /** |
||
731 | * Software fallback for glBlitFramebufferEXT(). |
||
732 | */ |
||
733 | void |
||
734 | _swrast_BlitFramebuffer(struct gl_context *ctx, |
||
735 | GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
736 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, |
||
737 | GLbitfield mask, GLenum filter) |
||
738 | { |
||
739 | static const GLbitfield buffers[3] = { |
||
740 | GL_COLOR_BUFFER_BIT, |
||
741 | GL_DEPTH_BUFFER_BIT, |
||
742 | GL_STENCIL_BUFFER_BIT |
||
743 | }; |
||
744 | static const GLenum buffer_enums[3] = { |
||
745 | GL_COLOR, |
||
746 | GL_DEPTH, |
||
747 | GL_STENCIL, |
||
748 | }; |
||
749 | GLint i; |
||
750 | |||
751 | if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, |
||
752 | &dstX0, &dstY0, &dstX1, &dstY1)) { |
||
753 | return; |
||
754 | } |
||
755 | |||
756 | if (SWRAST_CONTEXT(ctx)->NewState) |
||
757 | _swrast_validate_derived(ctx); |
||
758 | |||
759 | /* First, try covering whatever buffers possible using the fast 1:1 copy |
||
760 | * path. |
||
761 | */ |
||
762 | if (srcX1 - srcX0 == dstX1 - dstX0 && |
||
763 | srcY1 - srcY0 == dstY1 - dstY0 && |
||
764 | srcX0 < srcX1 && |
||
765 | srcY0 < srcY1 && |
||
766 | dstX0 < dstX1 && |
||
767 | dstY0 < dstY1) { |
||
768 | for (i = 0; i < 3; i++) { |
||
769 | if (mask & buffers[i]) { |
||
770 | if (swrast_fast_copy_pixels(ctx, |
||
771 | srcX0, srcY0, |
||
772 | srcX1 - srcX0, srcY1 - srcY0, |
||
773 | dstX0, dstY0, |
||
774 | buffer_enums[i])) { |
||
775 | mask &= ~buffers[i]; |
||
776 | } |
||
777 | } |
||
778 | } |
||
779 | |||
780 | if (!mask) |
||
781 | return; |
||
782 | } |
||
783 | |||
784 | if (filter == GL_NEAREST) { |
||
785 | for (i = 0; i < 3; i++) { |
||
786 | if (mask & buffers[i]) { |
||
787 | blit_nearest(ctx, srcX0, srcY0, srcX1, srcY1, |
||
788 | dstX0, dstY0, dstX1, dstY1, buffers[i]); |
||
789 | } |
||
790 | } |
||
791 | } |
||
792 | else { |
||
793 | ASSERT(filter == GL_LINEAR); |
||
794 | if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ |
||
795 | blit_linear(ctx, srcX0, srcY0, srcX1, srcY1, |
||
796 | dstX0, dstY0, dstX1, dstY1); |
||
797 | } |
||
798 | } |
||
799 | |||
800 | }>>>>>>>>>>>>=>>>=>>>>>>>>>>>>>>>> |