1 /************************************************************************** 2 * 3 * Copyright 2007 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 * Authors: 30 * Brian Paul 31 */ 32 33 #include "main/imports.h" 34 #include "main/image.h" 35 #include "main/macros.h" 36 #include "main/mfeatures.h" 37 38 #include "st_context.h" 39 #include "st_texture.h" 40 #include "st_cb_blit.h" 41 #include "st_cb_fbo.h" 42 #include "st_atom.h" 43 44 #include "util/u_blit.h" 45 46 47 void 48 st_init_blit(struct st_context *st) 49 { 50 st->blit = util_create_blit(st->pipe, st->cso_context); 51 } 52 53 54 void 55 st_destroy_blit(struct st_context *st) 56 { 57 util_destroy_blit(st->blit); 58 st->blit = NULL; 59 } 60 61 62 #if FEATURE_EXT_framebuffer_blit 63 64 static void 65 st_BlitFramebuffer_resolve(struct gl_context *ctx, 66 GLbitfield mask, 67 struct pipe_resolve_info *info) 68 { 69 const GLbitfield depthStencil = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; 70 71 struct st_context *st = st_context(ctx); 72 73 struct st_renderbuffer *srcRb, *dstRb; 74 75 if (mask & GL_COLOR_BUFFER_BIT) { 76 srcRb = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); 77 dstRb = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); 78 79 info->mask = PIPE_MASK_RGBA; 80 81 info->src.res = srcRb->texture; 82 info->src.layer = srcRb->surface->u.tex.first_layer; 83 info->dst.res = dstRb->texture; 84 info->dst.level = dstRb->surface->u.tex.level; 85 info->dst.layer = dstRb->surface->u.tex.first_layer; 86 87 st->pipe->resource_resolve(st->pipe, info); 88 } 89 90 if (mask & depthStencil) { 91 struct gl_renderbuffer_attachment *srcDepth, *srcStencil; 92 struct gl_renderbuffer_attachment *dstDepth, *dstStencil; 93 boolean combined; 94 95 srcDepth = &ctx->ReadBuffer->Attachment[BUFFER_DEPTH]; 96 dstDepth = &ctx->DrawBuffer->Attachment[BUFFER_DEPTH]; 97 srcStencil = &ctx->ReadBuffer->Attachment[BUFFER_STENCIL]; 98 dstStencil = &ctx->DrawBuffer->Attachment[BUFFER_STENCIL]; 99 100 combined = 101 st_is_depth_stencil_combined(srcDepth, srcStencil) && 102 st_is_depth_stencil_combined(dstDepth, dstStencil); 103 104 if ((mask & GL_DEPTH_BUFFER_BIT) || combined) { 105 /* resolve depth and, if combined and requested, stencil as well */ 106 srcRb = st_renderbuffer(srcDepth->Renderbuffer); 107 dstRb = st_renderbuffer(dstDepth->Renderbuffer); 108 109 info->mask = (mask & GL_DEPTH_BUFFER_BIT) ? PIPE_MASK_Z : 0; 110 if (combined && (mask & GL_STENCIL_BUFFER_BIT)) { 111 mask &= ~GL_STENCIL_BUFFER_BIT; 112 info->mask |= PIPE_MASK_S; 113 } 114 115 info->src.res = srcRb->texture; 116 info->src.layer = srcRb->surface->u.tex.first_layer; 117 info->dst.res = dstRb->texture; 118 info->dst.level = dstRb->surface->u.tex.level; 119 info->dst.layer = dstRb->surface->u.tex.first_layer; 120 121 st->pipe->resource_resolve(st->pipe, info); 122 } 123 124 if (mask & GL_STENCIL_BUFFER_BIT) { 125 /* resolve separate stencil buffer */ 126 srcRb = st_renderbuffer(srcStencil->Renderbuffer); 127 dstRb = st_renderbuffer(dstStencil->Renderbuffer); 128 129 info->mask = PIPE_MASK_S; 130 131 info->src.res = srcRb->texture; 132 info->src.layer = srcRb->surface->u.tex.first_layer; 133 info->dst.res = dstRb->texture; 134 info->dst.level = dstRb->surface->u.tex.level; 135 info->dst.layer = dstRb->surface->u.tex.first_layer; 136 137 st->pipe->resource_resolve(st->pipe, info); 138 } 139 } 140 } 141 142 static void 143 st_BlitFramebuffer(struct gl_context *ctx, 144 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 145 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 146 GLbitfield mask, GLenum filter) 147 { 148 const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | 149 GL_STENCIL_BUFFER_BIT); 150 struct st_context *st = st_context(ctx); 151 const uint pFilter = ((filter == GL_NEAREST) 152 ? PIPE_TEX_MIPFILTER_NEAREST 153 : PIPE_TEX_MIPFILTER_LINEAR); 154 struct gl_framebuffer *readFB = ctx->ReadBuffer; 155 struct gl_framebuffer *drawFB = ctx->DrawBuffer; 156 157 st_validate_state(st); 158 159 if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, 160 &dstX0, &dstY0, &dstX1, &dstY1)) { 161 return; /* nothing to draw/blit */ 162 } 163 164 if (st_fb_orientation(drawFB) == Y_0_TOP) { 165 /* invert Y for dest */ 166 dstY0 = drawFB->Height - dstY0; 167 dstY1 = drawFB->Height - dstY1; 168 } 169 170 if (st_fb_orientation(readFB) == Y_0_TOP) { 171 /* invert Y for src */ 172 srcY0 = readFB->Height - srcY0; 173 srcY1 = readFB->Height - srcY1; 174 } 175 176 /* Disable conditional rendering. */ 177 if (st->render_condition) { 178 st->pipe->render_condition(st->pipe, NULL, 0); 179 } 180 181 if (readFB->Visual.sampleBuffers > drawFB->Visual.sampleBuffers && 182 readFB->Visual.samples > 1) { 183 struct pipe_resolve_info info; 184 185 if (dstX0 < dstX1) { 186 info.dst.x0 = dstX0; 187 info.dst.x1 = dstX1; 188 info.src.x0 = srcX0; 189 info.src.x1 = srcX1; 190 } else { 191 info.dst.x0 = dstX1; 192 info.dst.x1 = dstX0; 193 info.src.x0 = srcX1; 194 info.src.x1 = srcX0; 195 } 196 if (dstY0 < dstY1) { 197 info.dst.y0 = dstY0; 198 info.dst.y1 = dstY1; 199 info.src.y0 = srcY0; 200 info.src.y1 = srcY1; 201 } else { 202 info.dst.y0 = dstY1; 203 info.dst.y1 = dstY0; 204 info.src.y0 = srcY1; 205 info.src.y1 = srcY0; 206 } 207 208 st_BlitFramebuffer_resolve(ctx, mask, &info); /* filter doesn't apply */ 209 210 goto done; 211 } 212 213 if (srcY0 > srcY1 && dstY0 > dstY1) { 214 /* Both src and dst are upside down. Swap Y to make it 215 * right-side up to increase odds of using a fast path. 216 * Recall that all Gallium raster coords have Y=0=top. 217 */ 218 GLint tmp; 219 tmp = srcY0; 220 srcY0 = srcY1; 221 srcY1 = tmp; 222 tmp = dstY0; 223 dstY0 = dstY1; 224 dstY1 = tmp; 225 } 226 227 if (mask & GL_COLOR_BUFFER_BIT) { 228 struct gl_renderbuffer_attachment *srcAtt = 229 &readFB->Attachment[readFB->_ColorReadBufferIndex]; 230 231 if(srcAtt->Type == GL_TEXTURE) { 232 struct st_texture_object *srcObj = 233 st_texture_object(srcAtt->Texture); 234 struct st_renderbuffer *dstRb = 235 st_renderbuffer(drawFB->_ColorDrawBuffers[0]); 236 struct pipe_surface *dstSurf = dstRb->surface; 237 238 if (!srcObj->pt) 239 goto done; 240 241 util_blit_pixels(st->blit, srcObj->pt, srcAtt->TextureLevel, 242 srcX0, srcY0, srcX1, srcY1, 243 srcAtt->Zoffset + srcAtt->CubeMapFace, 244 dstSurf, dstX0, dstY0, dstX1, dstY1, 245 0.0, pFilter, TGSI_WRITEMASK_XYZW, 0); 246 } 247 else { 248 struct st_renderbuffer *srcRb = 249 st_renderbuffer(readFB->_ColorReadBuffer); 250 struct st_renderbuffer *dstRb = 251 st_renderbuffer(drawFB->_ColorDrawBuffers[0]); 252 struct pipe_surface *srcSurf = srcRb->surface; 253 struct pipe_surface *dstSurf = dstRb->surface; 254 255 util_blit_pixels(st->blit, 256 srcRb->texture, srcSurf->u.tex.level, 257 srcX0, srcY0, srcX1, srcY1, 258 srcSurf->u.tex.first_layer, 259 dstSurf, dstX0, dstY0, dstX1, dstY1, 260 0.0, pFilter, TGSI_WRITEMASK_XYZW, 0); 261 } 262 } 263 264 if (mask & depthStencil) { 265 /* depth and/or stencil blit */ 266 267 /* get src/dst depth surfaces */ 268 struct gl_renderbuffer_attachment *srcDepth = 269 &readFB->Attachment[BUFFER_DEPTH]; 270 struct gl_renderbuffer_attachment *dstDepth = 271 &drawFB->Attachment[BUFFER_DEPTH]; 272 struct gl_renderbuffer_attachment *srcStencil = 273 &readFB->Attachment[BUFFER_STENCIL]; 274 struct gl_renderbuffer_attachment *dstStencil = 275 &drawFB->Attachment[BUFFER_STENCIL]; 276 277 struct st_renderbuffer *srcDepthRb = 278 st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); 279 struct st_renderbuffer *dstDepthRb = 280 st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); 281 struct pipe_surface *dstDepthSurf = 282 dstDepthRb ? dstDepthRb->surface : NULL; 283 284 struct st_renderbuffer *srcStencilRb = 285 st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer); 286 struct st_renderbuffer *dstStencilRb = 287 st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer); 288 struct pipe_surface *dstStencilSurf = 289 dstStencilRb ? dstStencilRb->surface : NULL; 290 291 if ((mask & depthStencil) == depthStencil && 292 st_is_depth_stencil_combined(srcDepth, srcStencil) && 293 st_is_depth_stencil_combined(dstDepth, dstStencil)) { 294 295 /* Blitting depth and stencil values between combined 296 * depth/stencil buffers. This is the ideal case for such buffers. 297 */ 298 util_blit_pixels(st->blit, 299 srcDepthRb->texture, 300 srcDepthRb->surface->u.tex.level, 301 srcX0, srcY0, srcX1, srcY1, 302 srcDepthRb->surface->u.tex.first_layer, 303 dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 304 0.0, pFilter, 0, 305 BLIT_WRITEMASK_Z | 306 (st->has_stencil_export ? BLIT_WRITEMASK_STENCIL 307 : 0)); 308 309 if (!st->has_stencil_export) { 310 _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) " 311 "software fallback not implemented"); 312 } 313 } 314 else { 315 /* blitting depth and stencil separately */ 316 317 if (mask & GL_DEPTH_BUFFER_BIT) { 318 util_blit_pixels(st->blit, srcDepthRb->texture, 319 srcDepthRb->surface->u.tex.level, 320 srcX0, srcY0, srcX1, srcY1, 321 srcDepthRb->surface->u.tex.first_layer, 322 dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 323 0.0, pFilter, 0, BLIT_WRITEMASK_Z); 324 } 325 326 if (mask & GL_STENCIL_BUFFER_BIT) { 327 if (st->has_stencil_export) { 328 util_blit_pixels(st->blit, srcStencilRb->texture, 329 srcStencilRb->surface->u.tex.level, 330 srcX0, srcY0, srcX1, srcY1, 331 srcStencilRb->surface->u.tex.first_layer, 332 dstStencilSurf, dstX0, dstY0, dstX1, dstY1, 333 0.0, pFilter, 0, BLIT_WRITEMASK_STENCIL); 334 } 335 else { 336 _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) " 337 "software fallback not implemented"); 338 } 339 } 340 } 341 } 342 343 done: 344 /* Restore conditional rendering state. */ 345 if (st->render_condition) { 346 st->pipe->render_condition(st->pipe, st->render_condition, 347 st->condition_mode); 348 } 349 } 350 351 352 void 353 st_init_blit_functions(struct dd_function_table *functions) 354 { 355 functions->BlitFramebuffer = st_BlitFramebuffer; 356 } 357 358 #endif /* FEATURE_EXT_framebuffer_blit */ 359