Merge branch '965-glsl'
[mesa.git] / src / mesa / drivers / dri / i965 / intel_pixel_copy.c
1 /**************************************************************************
2 *
3 * Copyright 2003 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 #include "glheader.h"
29 #include "enums.h"
30 #include "image.h"
31 #include "mtypes.h"
32 #include "macros.h"
33 #include "state.h"
34 #include "swrast/swrast.h"
35
36 #include "intel_screen.h"
37 #include "intel_context.h"
38 #include "intel_ioctl.h"
39 #include "intel_batchbuffer.h"
40 #include "intel_blit.h"
41 #include "intel_regions.h"
42
43
44 static struct intel_region *
45 copypix_src_region(struct intel_context *intel, GLenum type)
46 {
47 switch (type) {
48 case GL_COLOR:
49 return intel_readbuf_region(intel);
50 case GL_DEPTH:
51 /* Don't think this is really possible execpt at 16bpp, when we have no stencil.
52 */
53 if (intel->depth_region && intel->depth_region->cpp == 2)
54 return intel->depth_region;
55 case GL_STENCIL:
56 /* Don't think this is really possible.
57 */
58 break;
59 case GL_DEPTH_STENCIL_EXT:
60 /* Does it matter whether it is stencil/depth or depth/stencil?
61 */
62 return intel->depth_region;
63 default:
64 break;
65 }
66
67 return NULL;
68 }
69
70
71
72
73 /**
74 * Check if any fragment operations are in effect which might effect
75 * glDraw/CopyPixels.
76 */
77 GLboolean
78 intel_check_blit_fragment_ops(GLcontext * ctx)
79 {
80 if (ctx->NewState)
81 _mesa_update_state(ctx);
82
83 return !(ctx->_ImageTransferState ||
84 ctx->RenderMode != GL_RENDER ||
85 ctx->Color.AlphaEnabled ||
86 ctx->Depth.Test ||
87 ctx->Fog.Enabled ||
88 ctx->Stencil.Enabled ||
89 !ctx->Color.ColorMask[0] ||
90 !ctx->Color.ColorMask[1] ||
91 !ctx->Color.ColorMask[2] ||
92 !ctx->Color.ColorMask[3] || /* can do this! */
93 ctx->Texture._EnabledUnits ||
94 ctx->FragmentProgram._Enabled ||
95 ctx->Color.BlendEnabled);
96 }
97
98 /* Doesn't work for overlapping regions. Could do a double copy or
99 * just fallback.
100 */
101 static GLboolean
102 do_texture_copypixels(GLcontext * ctx,
103 GLint srcx, GLint srcy,
104 GLsizei width, GLsizei height,
105 GLint dstx, GLint dsty, GLenum type)
106 {
107 struct intel_context *intel = intel_context(ctx);
108 struct intel_region *dst = intel_drawbuf_region(intel);
109 struct intel_region *src = copypix_src_region(intel, type);
110 GLenum src_format;
111 GLenum src_type;
112
113 DBG("%s %d,%d %dx%d --> %d,%d\n", __FUNCTION__,
114 srcx, srcy, width, height, dstx, dsty);
115
116 if (!src || !dst || type != GL_COLOR ||
117 ctx->_ImageTransferState ||
118 ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F ||
119 ctx->RenderMode != GL_RENDER ||
120 ctx->Texture._EnabledUnits ||
121 ctx->FragmentProgram._Enabled ||
122 src != dst )
123 return GL_FALSE;
124
125 /* Can't handle overlapping regions. Don't have sufficient control
126 * over rasterization to pull it off in-place. Punt on these for
127 * now.
128 *
129 * XXX: do a copy to a temporary.
130 */
131 if (src->buffer == dst->buffer) {
132 drm_clip_rect_t srcbox;
133 drm_clip_rect_t dstbox;
134 drm_clip_rect_t tmp;
135
136 srcbox.x1 = srcx;
137 srcbox.y1 = srcy;
138 srcbox.x2 = srcx + width - 1;
139 srcbox.y2 = srcy + height - 1;
140
141 dstbox.x1 = dstx;
142 dstbox.y1 = dsty;
143 dstbox.x2 = dstx + width - 1;
144 dstbox.y2 = dsty + height - 1;
145
146 DBG("src %d,%d %d,%d\n", srcbox.x1, srcbox.y1, srcbox.x2, srcbox.y2);
147 DBG("dst %d,%d %d,%d (%dx%d) (%f,%f)\n", dstbox.x1, dstbox.y1, dstbox.x2, dstbox.y2,
148 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
149
150 if (intel_intersect_cliprects(&tmp, &srcbox, &dstbox)) {
151 DBG("%s: regions overlap\n", __FUNCTION__);
152 return GL_FALSE;
153 }
154 }
155
156 intelFlush(&intel->ctx);
157
158 intel->vtbl.install_meta_state(intel);
159
160 /* Is this true? Also will need to turn depth testing on according
161 * to state:
162 */
163 intel->vtbl.meta_no_stencil_write(intel);
164 intel->vtbl.meta_no_depth_write(intel);
165
166 /* Set the 3d engine to draw into the destination region:
167 */
168 intel->vtbl.meta_draw_region(intel, dst, intel->depth_region);
169
170 intel->vtbl.meta_import_pixel_state(intel);
171
172 if (src->cpp == 2) {
173 src_format = GL_RGB;
174 src_type = GL_UNSIGNED_SHORT_5_6_5;
175 }
176 else {
177 src_format = GL_BGRA;
178 src_type = GL_UNSIGNED_BYTE;
179 }
180
181 /* Set the frontbuffer up as a large rectangular texture.
182 */
183 intel->vtbl.meta_frame_buffer_texture( intel, srcx - dstx, srcy - dsty );
184
185 intel->vtbl.meta_texture_blend_replace(intel);
186
187 if (intel->driDrawable->numClipRects)
188 intel->vtbl.meta_draw_quad( intel,
189 dstx, dstx + width,
190 dsty, dsty + height,
191 ctx->Current.RasterPos[ 2 ],
192 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0 );
193
194 intel->vtbl.leave_meta_state( intel );
195
196 DBG("%s: success\n", __FUNCTION__);
197 return GL_TRUE;
198 }
199
200 /**
201 * CopyPixels with the blitter. Don't support zooming, pixel transfer, etc.
202 */
203 static GLboolean
204 do_blit_copypixels(GLcontext * ctx,
205 GLint srcx, GLint srcy,
206 GLsizei width, GLsizei height,
207 GLint dstx, GLint dsty, GLenum type)
208 {
209 struct intel_context *intel = intel_context(ctx);
210 struct intel_region *dst = intel_drawbuf_region(intel);
211 struct intel_region *src = copypix_src_region(intel, type);
212
213 /* Copypixels can be more than a straight copy. Ensure all the
214 * extra operations are disabled:
215 */
216 if (!intel_check_blit_fragment_ops(ctx) ||
217 ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F)
218 return GL_FALSE;
219
220 if (!src || !dst)
221 return GL_FALSE;
222
223
224
225 intelFlush(&intel->ctx);
226
227 /* intel->vtbl.render_start(intel); */
228 /* intel->vtbl.emit_state(intel); */
229
230 LOCK_HARDWARE(intel);
231
232 if (intel->driDrawable->numClipRects) {
233 __DRIdrawablePrivate *dPriv = intel->driDrawable;
234 __DRIdrawablePrivate *dReadPriv = intel->driReadDrawable;
235 drm_clip_rect_t *box = dPriv->pClipRects;
236 drm_clip_rect_t dest_rect;
237 GLint nbox = dPriv->numClipRects;
238 GLint delta_x = 0;
239 GLint delta_y = 0;
240 GLuint i;
241
242 /* Do scissoring in GL coordinates:
243 */
244 if (ctx->Scissor.Enabled)
245 {
246 GLint x = ctx->Scissor.X;
247 GLint y = ctx->Scissor.Y;
248 GLuint w = ctx->Scissor.Width;
249 GLuint h = ctx->Scissor.Height;
250 GLint dx = dstx - srcx;
251 GLint dy = dsty - srcy;
252
253 if (!_mesa_clip_to_region(x, y, x+w-1, y+h-1, &dstx, &dsty, &width, &height))
254 goto out;
255
256 srcx = dstx - dx;
257 srcy = dsty - dy;
258 }
259
260 /* Convert from GL to hardware coordinates:
261 */
262 dsty = dPriv->h - dsty - height;
263 srcy = dPriv->h - srcy - height;
264 dstx += dPriv->x;
265 dsty += dPriv->y;
266 srcx += dReadPriv->x;
267 srcy += dReadPriv->y;
268
269 /* Clip against the source region. This is the only source
270 * clipping we do. Dst is clipped with cliprects below.
271 */
272 {
273 delta_x = srcx - dstx;
274 delta_y = srcy - dsty;
275
276 if (!_mesa_clip_to_region(0, 0, src->pitch, src->height,
277 &srcx, &srcy, &width, &height))
278 goto out;
279
280 dstx = srcx - delta_x;
281 dsty = srcy - delta_y;
282 }
283
284 dest_rect.x1 = dstx;
285 dest_rect.y1 = dsty;
286 dest_rect.x2 = dstx + width;
287 dest_rect.y2 = dsty + height;
288
289 /* intel->vtbl.emit_flush(intel, 0); */
290
291 /* Could do slightly more clipping: Eg, take the intersection of
292 * the existing set of cliprects and those cliprects translated
293 * by delta_x, delta_y:
294 *
295 * This code will not overwrite other windows, but will
296 * introduce garbage when copying from obscured window regions.
297 */
298 for (i = 0; i < nbox; i++) {
299 drm_clip_rect_t rect;
300
301 if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i]))
302 continue;
303
304
305 intelEmitCopyBlit(intel,
306 dst->cpp,
307 src->pitch, src->buffer, 0, src->tiled,
308 dst->pitch, dst->buffer, 0, dst->tiled,
309 rect.x1 + delta_x,
310 rect.y1 + delta_y, /* srcx, srcy */
311 rect.x1, rect.y1, /* dstx, dsty */
312 rect.x2 - rect.x1, rect.y2 - rect.y1,
313 ctx->Color.ColorLogicOpEnabled ?
314 ctx->Color.LogicOp : GL_COPY);
315 }
316
317 intel->need_flush = GL_TRUE;
318 out:
319 intel_batchbuffer_flush(intel->batch);
320 }
321 UNLOCK_HARDWARE(intel);
322 return GL_TRUE;
323 }
324
325 void
326 intelCopyPixels(GLcontext * ctx,
327 GLint srcx, GLint srcy,
328 GLsizei width, GLsizei height,
329 GLint destx, GLint desty, GLenum type)
330 {
331 if (INTEL_DEBUG & DEBUG_PIXEL)
332 fprintf(stderr, "%s\n", __FUNCTION__);
333
334 if (do_blit_copypixels(ctx, srcx, srcy, width, height, destx, desty, type))
335 return;
336
337 if (do_texture_copypixels(ctx, srcx, srcy, width, height, destx, desty, type))
338 return;
339
340 if (INTEL_DEBUG & DEBUG_PIXEL)
341 _mesa_printf("fallback to _swrast_CopyPixels\n");
342
343 _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type);
344 }