/** * \brief Call this after drawing to mark which buffers need resolving * * If the depth buffer was written to and if it has an accompanying HiZ * buffer, then mark that it needs a depth resolve. * * If the color buffer is a multisample window system buffer, then * mark that it needs a downsample. * * Also mark any render targets which will be textured as needing a render * cache flush. */ static void brw_postdraw_set_buffers_need_resolve(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *front_irb = NULL; struct intel_renderbuffer *back_irb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct gl_renderbuffer_attachment *depth_att = &fb->Attachment[BUFFER_DEPTH]; if (_mesa_is_front_buffer_drawing(fb)) front_irb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); if (front_irb) front_irb->need_downsample = true; if (back_irb) back_irb->need_downsample = true; if (depth_irb && ctx->Depth.Mask) { intel_renderbuffer_att_set_needs_depth_resolve(depth_att); brw_render_cache_set_add_bo(brw, depth_irb->mt->bo); } if (ctx->Extensions.ARB_stencil_texturing && stencil_irb && ctx->Stencil._WriteEnabled) { brw_render_cache_set_add_bo(brw, stencil_irb->mt->bo); } for (unsigned i = 0; i < fb->_NumColorDrawBuffers; i++) { struct intel_renderbuffer *irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]); if (irb) brw_render_cache_set_add_bo(brw, irb->mt->bo); } }
bool brw_blorp_clear_color(struct intel_context *intel, struct gl_framebuffer *fb) { struct gl_context *ctx = &intel->ctx; struct brw_context *brw = brw_context(ctx); /* The constant color clear code doesn't work for multisampled surfaces, so * we need to support falling back to other clear mechanisms. * Unfortunately, our clear code is based on a bitmask that doesn't * distinguish individual color attachments, so we walk the attachments to * see if any require fallback, and fall back for all if any of them need * to. */ for (unsigned buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (irb && irb->mt->msaa_layout != INTEL_MSAA_LAYOUT_NONE) return false; } for (unsigned buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf]; /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported, * the framebuffer can be complete with some attachments missing. In * this case the _ColorDrawBuffers pointer will be NULL. */ if (rb == NULL) continue; brw_blorp_clear_params params(brw, fb, rb, ctx->Color.ColorMask[buf]); brw_blorp_exec(intel, ¶ms); } return true; }
static void intelCopyTexSubImage(struct gl_context *ctx, GLuint dims, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, GLint slice, struct gl_renderbuffer *rb, GLint x, GLint y, GLsizei width, GLsizei height) { struct intel_context *intel = intel_context(ctx); /* Try the BLT engine. */ if (intel_copy_texsubimage(intel, intel_texture_image(texImage), xoffset, yoffset, slice, intel_renderbuffer(rb), x, y, width, height)) { return; } /* Otherwise, fall back to meta. This will likely be slow. */ perf_debug("%s - fallback to swrast\n", __FUNCTION__); _mesa_meta_CopyTexSubImage(ctx, dims, texImage, xoffset, yoffset, slice, rb, x, y, width, height); }
bool brw_blorp_clear_color(struct brw_context *brw, struct gl_framebuffer *fb, bool partial_clear) { struct gl_context *ctx = &brw->ctx; /* The constant color clear code doesn't work for multisampled surfaces, so * we need to support falling back to other clear mechanisms. * Unfortunately, our clear code is based on a bitmask that doesn't * distinguish individual color attachments, so we walk the attachments to * see if any require fallback, and fall back for all if any of them need * to. */ for (unsigned buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (irb && irb->mt->msaa_layout != INTEL_MSAA_LAYOUT_NONE) return false; } for (unsigned buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported, * the framebuffer can be complete with some attachments missing. In * this case the _ColorDrawBuffers pointer will be NULL. */ if (rb == NULL) continue; brw_blorp_clear_params params(brw, fb, rb, ctx->Color.ColorMask[buf], partial_clear); bool is_fast_clear = (params.fast_clear_op == GEN7_FAST_CLEAR_OP_FAST_CLEAR); if (is_fast_clear) { /* Record the clear color in the miptree so that it will be * programmed in SURFACE_STATE by later rendering and resolve * operations. */ uint32_t new_color_value = compute_fast_clear_color_bits(&ctx->Color.ClearColor); if (irb->mt->fast_clear_color_value != new_color_value) { irb->mt->fast_clear_color_value = new_color_value; brw->state.dirty.brw |= BRW_NEW_SURFACES; } /* If the buffer is already in INTEL_MCS_STATE_CLEAR, the clear is * redundant and can be skipped. */ if (irb->mt->mcs_state == INTEL_MCS_STATE_CLEAR) continue; /* If the MCS buffer hasn't been allocated yet, we need to allocate * it now. */ if (!irb->mt->mcs_mt) { if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) { /* MCS allocation failed--probably this will only happen in * out-of-memory conditions. But in any case, try to recover * by falling back to a non-blorp clear technique. */ return false; } brw->state.dirty.brw |= BRW_NEW_SURFACES; } } DBG("%s to mt %p level %d layer %d\n", __FUNCTION__, irb->mt, irb->mt_level, irb->mt_layer); brw_blorp_exec(brw, ¶ms); if (is_fast_clear) { /* Now that the fast clear has occurred, put the buffer in * INTEL_MCS_STATE_CLEAR so that we won't waste time doing redundant * clears. */ irb->mt->mcs_state = INTEL_MCS_STATE_CLEAR; } } return true; }
/** * Sets up a surface state structure to point at the given region. * While it is only used for the front/back buffer currently, it should be * usable for further buffers when doing ARB_draw_buffer support. */ static void brw_update_renderbuffer_surface(struct brw_context *brw, struct gl_renderbuffer *rb, unsigned int unit) { struct intel_context *intel = &brw->intel; GLcontext *ctx = &intel->ctx; dri_bo *region_bo = NULL; struct intel_renderbuffer *irb = intel_renderbuffer(rb); struct intel_region *region = irb ? irb->region : NULL; struct { unsigned int surface_type; unsigned int surface_format; unsigned int width, height, pitch, cpp; GLubyte color_mask[4]; GLboolean color_blend; uint32_t tiling; uint32_t draw_x; uint32_t draw_y; } key; memset(&key, 0, sizeof(key)); if (region != NULL) { region_bo = region->buffer; key.surface_type = BRW_SURFACE_2D; switch (irb->Base.Format) { /* XRGB and ARGB are treated the same here because the chips in this * family cannot render to XRGB targets. This means that we have to * mask writes to alpha (ala glColorMask) and reconfigure the alpha * blending hardware to use GL_ONE (or GL_ZERO) for cases where * GL_DST_ALPHA (or GL_ONE_MINUS_DST_ALPHA) is used. */ case MESA_FORMAT_ARGB8888: case MESA_FORMAT_XRGB8888: key.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM; break; case MESA_FORMAT_RGB565: key.surface_format = BRW_SURFACEFORMAT_B5G6R5_UNORM; break; case MESA_FORMAT_ARGB1555: key.surface_format = BRW_SURFACEFORMAT_B5G5R5A1_UNORM; break; case MESA_FORMAT_ARGB4444: key.surface_format = BRW_SURFACEFORMAT_B4G4R4A4_UNORM; break; default: _mesa_problem(ctx, "Bad renderbuffer format: %d\n", irb->Base.Format); } key.tiling = region->tiling; if (brw->intel.intelScreen->driScrnPriv->dri2.enabled) { key.width = rb->Width; key.height = rb->Height; } else { key.width = region->width; key.height = region->height; } key.pitch = region->pitch; key.cpp = region->cpp; key.draw_x = region->draw_x; key.draw_y = region->draw_y; } else { key.surface_type = BRW_SURFACE_NULL; key.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM; key.tiling = I915_TILING_X; key.width = 1; key.height = 1; key.cpp = 4; key.draw_x = 0; key.draw_y = 0; } if (intel->gen < 6) { /* _NEW_COLOR */ memcpy(key.color_mask, ctx->Color.ColorMask[unit], sizeof(key.color_mask)); /* As mentioned above, disable writes to the alpha component when the * renderbuffer is XRGB. */ if (ctx->DrawBuffer->Visual.alphaBits == 0) key.color_mask[3] = GL_FALSE; key.color_blend = (!ctx->Color._LogicOpEnabled && (ctx->Color.BlendEnabled & (1 << unit))); } dri_bo_unreference(brw->wm.surf_bo[unit]); brw->wm.surf_bo[unit] = brw_search_cache(&brw->surface_cache, BRW_SS_SURFACE, &key, sizeof(key), ®ion_bo, 1, NULL); if (brw->wm.surf_bo[unit] == NULL) { struct brw_surface_state surf; memset(&surf, 0, sizeof(surf)); surf.ss0.surface_format = key.surface_format; surf.ss0.surface_type = key.surface_type; if (key.tiling == I915_TILING_NONE) { surf.ss1.base_addr = (key.draw_x + key.draw_y * key.pitch) * key.cpp; } else { uint32_t tile_base, tile_x, tile_y; uint32_t pitch = key.pitch * key.cpp; if (key.tiling == I915_TILING_X) { tile_x = key.draw_x % (512 / key.cpp); tile_y = key.draw_y % 8; tile_base = ((key.draw_y / 8) * (8 * pitch)); tile_base += (key.draw_x - tile_x) / (512 / key.cpp) * 4096; } else { /* Y */ tile_x = key.draw_x % (128 / key.cpp); tile_y = key.draw_y % 32; tile_base = ((key.draw_y / 32) * (32 * pitch)); tile_base += (key.draw_x - tile_x) / (128 / key.cpp) * 4096; } assert(brw->has_surface_tile_offset || (tile_x == 0 && tile_y == 0)); assert(tile_x % 4 == 0); assert(tile_y % 2 == 0); /* Note that the low bits of these fields are missing, so * there's the possibility of getting in trouble. */ surf.ss1.base_addr = tile_base; surf.ss5.x_offset = tile_x / 4; surf.ss5.y_offset = tile_y / 2; } if (region_bo != NULL) surf.ss1.base_addr += region_bo->offset; /* reloc */ surf.ss2.width = key.width - 1; surf.ss2.height = key.height - 1; brw_set_surface_tiling(&surf, key.tiling); surf.ss3.pitch = (key.pitch * key.cpp) - 1; if (intel->gen < 6) { /* _NEW_COLOR */ surf.ss0.color_blend = key.color_blend; surf.ss0.writedisable_red = !key.color_mask[0]; surf.ss0.writedisable_green = !key.color_mask[1]; surf.ss0.writedisable_blue = !key.color_mask[2]; surf.ss0.writedisable_alpha = !key.color_mask[3]; } /* Key size will never match key size for textures, so we're safe. */ brw->wm.surf_bo[unit] = brw_upload_cache(&brw->surface_cache, BRW_SS_SURFACE, &key, sizeof(key), ®ion_bo, 1, &surf, sizeof(surf)); if (region_bo != NULL) { /* We might sample from it, and we might render to it, so flag * them both. We might be able to figure out from other state * a more restrictive relocation to emit. */ drm_intel_bo_emit_reloc(brw->wm.surf_bo[unit], offsetof(struct brw_surface_state, ss1), region_bo, surf.ss1.base_addr - region_bo->offset, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); } }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); const struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); const struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; DBG("%s() on fb %p (%s)\n", __FUNCTION__, fb, (fb == ctx->DrawBuffer ? "drawbuffer" : (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); if (depthRb) depth_mt = depthRb->mt; if (stencilRb) { stencil_mt = stencilRb->mt; if (stencil_mt->stencil_mt) stencil_mt = stencil_mt->stencil_mt; } if (depth_mt && stencil_mt) { if (depth_mt == stencil_mt) { /* For true packed depth/stencil (not faked on prefers-separate-stencil * hardware) we need to be sure they're the same level/layer, since * we'll be emitting a single packet describing the packed setup. */ if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { DBG("depth image level/layer %d/%d != stencil image %d/%d\n", depthRb->mt_level, depthRb->mt_layer, stencilRb->mt_level, stencilRb->mt_layer); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } } else { if (!intel->has_separate_stencil) { DBG("separate stencil unsupported\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } if (stencil_mt->format != MESA_FORMAT_S8) { DBG("separate stencil is %s instead of S8\n", _mesa_get_format_name(stencil_mt->format)); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } if (intel->gen < 7 && depth_mt->hiz_mt == NULL) { /* Before Gen7, separate depth and stencil buffers can be used * only if HiZ is enabled. From the Sandybridge PRM, Volume 2, * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable: * [DevSNB]: This field must be set to the same value (enabled * or disabled) as Hierarchical Depth Buffer Enable. */ DBG("separate stencil without HiZ\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; } } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { DBG("attachment without renderbuffer\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { const struct gl_texture_image *img = _mesa_get_attachment_teximage_const(&fb->Attachment[i]); if (img->Border) { DBG("texture with border\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { DBG("software rendering renderbuffer\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } if (!intel->vtbl.render_target_supported(intel, rb)) { DBG("Unsupported HW texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } } }
/** * Update the hardware state for drawing into a window or framebuffer object. * * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other * places within the driver. * * Basically, this needs to be called any time the current framebuffer * changes, the renderbuffers change, or we need to draw into different * color buffers. */ void intel_draw_buffer(struct gl_context * ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); struct intel_region *colorRegions[MAX_DRAW_BUFFERS], *depthRegion = NULL; struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL; if (!fb) { /* this can happen during the initial context initialization */ return; } /* Do this here, not core Mesa, since this function is called from * many places within the driver. */ if (ctx->NewState & _NEW_BUFFERS) { /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */ _mesa_update_framebuffer(ctx); /* this updates the DrawBuffer's Width/Height if it's a FBO */ _mesa_update_draw_buffer_bounds(ctx); } if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { /* this may occur when we're called by glBindFrameBuffer() during * the process of someone setting up renderbuffers, etc. */ /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/ return; } /* How many color buffers are we drawing into? * * If there are zero buffers or the buffer is too big, don't configure any * regions for hardware drawing. We'll fallback to software below. Not * having regions set makes some of the software fallback paths faster. */ if ((fb->Width > ctx->Const.MaxRenderbufferSize) || (fb->Height > ctx->Const.MaxRenderbufferSize) || (fb->_NumColorDrawBuffers == 0)) { /* writing to 0 */ colorRegions[0] = NULL; } else if (fb->_NumColorDrawBuffers > 1) { int i; struct intel_renderbuffer *irb; for (i = 0; i < fb->_NumColorDrawBuffers; i++) { irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]); colorRegions[i] = irb ? irb->region : NULL; } } else { /* Get the intel_renderbuffer for the single colorbuffer we're drawing * into. */ if (fb->Name == 0) { /* drawing to window system buffer */ if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) colorRegions[0] = intel_get_rb_region(fb, BUFFER_FRONT_LEFT); else colorRegions[0] = intel_get_rb_region(fb, BUFFER_BACK_LEFT); } else { /* drawing to user-created FBO */ struct intel_renderbuffer *irb; irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); colorRegions[0] = (irb && irb->region) ? irb->region : NULL; } } if (!colorRegions[0]) { FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); } else { FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); } /*** *** Get depth buffer region and check if we need a software fallback. *** Note that the depth buffer is usually a DEPTH_STENCIL buffer. ***/ if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) { irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped); if (irbDepth && irbDepth->region) { FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); depthRegion = irbDepth->region; } else { FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE); depthRegion = NULL; } } else { /* not using depth buffer */ FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); depthRegion = NULL; } /*** *** Stencil buffer *** This can only be hardware accelerated if we're using a *** combined DEPTH_STENCIL buffer. ***/ if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) { irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped); if (irbStencil && irbStencil->region) { ASSERT(irbStencil->Base.Format == MESA_FORMAT_S8_Z24); FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); } else { FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE); } } else { /* XXX FBO: instead of FALSE, pass ctx->Stencil._Enabled ??? */ FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); } /* If we have a (packed) stencil buffer attached but no depth buffer, * we still need to set up the shared depth/stencil state so we can use it. */ if (depthRegion == NULL && irbStencil && irbStencil->region) depthRegion = irbStencil->region; /* * Update depth and stencil test state */ if (ctx->Driver.Enable) { ctx->Driver.Enable(ctx, GL_DEPTH_TEST, (ctx->Depth.Test && fb->Visual.depthBits > 0)); ctx->Driver.Enable(ctx, GL_STENCIL_TEST, (ctx->Stencil.Enabled && fb->Visual.stencilBits > 0)); } else { /* Mesa's Stencil._Enabled field is updated when * _NEW_BUFFERS | _NEW_STENCIL, but i965 code assumes that the value * only changes with _NEW_STENCIL (which seems sensible). So flag it * here since this is the _NEW_BUFFERS path. */ intel->NewGLState |= (_NEW_DEPTH | _NEW_STENCIL); } intel->vtbl.set_draw_region(intel, colorRegions, depthRegion, fb->_NumColorDrawBuffers); intel->NewGLState |= _NEW_BUFFERS; /* update viewport since it depends on window size */ #ifdef I915 intelCalcViewport(ctx); #else intel->NewGLState |= _NEW_VIEWPORT; #endif /* Set state we know depends on drawable parameters: */ if (ctx->Driver.Scissor) ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, ctx->Scissor.Width, ctx->Scissor.Height); intel->NewGLState |= _NEW_SCISSOR; if (ctx->Driver.DepthRange) ctx->Driver.DepthRange(ctx, ctx->Viewport.Near, ctx->Viewport.Far); /* Update culling direction which changes depending on the * orientation of the buffer: */ if (ctx->Driver.FrontFace) ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace); else intel->NewGLState |= _NEW_POLYGON; }
/** * CopyPixels with the blitter. Don't support zooming, pixel transfer, etc. */ static GLboolean do_blit_copypixels(struct gl_context * ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_framebuffer *read_fb = ctx->ReadBuffer; GLint orig_dstx; GLint orig_dsty; GLint orig_srcx; GLint orig_srcy; GLboolean flip = GL_FALSE; struct intel_renderbuffer *draw_irb = NULL; struct intel_renderbuffer *read_irb = NULL; /* Update draw buffer bounds */ _mesa_update_state(ctx); switch (type) { case GL_COLOR: if (fb->_NumColorDrawBuffers != 1) { fallback_debug("glCopyPixels() fallback: MRT\n"); return GL_FALSE; } draw_irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); read_irb = intel_renderbuffer(read_fb->_ColorReadBuffer); break; case GL_DEPTH_STENCIL_EXT: draw_irb = intel_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); read_irb = intel_renderbuffer(read_fb->Attachment[BUFFER_DEPTH].Renderbuffer); break; case GL_DEPTH: fallback_debug("glCopyPixels() fallback: GL_DEPTH\n"); return GL_FALSE; case GL_STENCIL: fallback_debug("glCopyPixels() fallback: GL_STENCIL\n"); return GL_FALSE; default: fallback_debug("glCopyPixels(): Unknown type\n"); return GL_FALSE; } if (!draw_irb) { fallback_debug("glCopyPixels() fallback: missing draw buffer\n"); return GL_FALSE; } if (!read_irb) { fallback_debug("glCopyPixels() fallback: missing read buffer\n"); return GL_FALSE; } if (draw_irb->Base.Format != read_irb->Base.Format && !(draw_irb->Base.Format == MESA_FORMAT_XRGB8888 && read_irb->Base.Format == MESA_FORMAT_ARGB8888)) { fallback_debug("glCopyPixels() fallback: mismatched formats (%s -> %s\n", _mesa_get_format_name(read_irb->Base.Format), _mesa_get_format_name(draw_irb->Base.Format)); return GL_FALSE; } /* Copypixels can be more than a straight copy. Ensure all the * extra operations are disabled: */ if (!intel_check_copypixel_blit_fragment_ops(ctx) || ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F) return GL_FALSE; intel_prepare_render(intel); intel_flush(&intel->ctx); /* Clip to destination buffer. */ orig_dstx = dstx; orig_dsty = dsty; if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; /* Adjust src coords for our post-clipped destination origin */ srcx += dstx - orig_dstx; srcy += dsty - orig_dsty; /* Clip to source buffer. */ orig_srcx = srcx; orig_srcy = srcy; if (!_mesa_clip_to_region(0, 0, read_fb->Width, read_fb->Height, &srcx, &srcy, &width, &height)) goto out; /* Adjust dst coords for our post-clipped source origin */ dstx += srcx - orig_srcx; dsty += srcy - orig_srcy; /* Flip dest Y if it's a window system framebuffer. */ if (fb->Name == 0) { /* copypixels to a window system framebuffer */ dsty = fb->Height - dsty - height; flip = !flip; } /* Flip source Y if it's a window system framebuffer. */ if (read_fb->Name == 0) { srcy = read_fb->Height - srcy - height; flip = !flip; } srcx += read_irb->draw_x; srcy += read_irb->draw_y; dstx += draw_irb->draw_x; dsty += draw_irb->draw_y; if (!intel_region_copy(intel, draw_irb->region, 0, dstx, dsty, read_irb->region, 0, srcx, srcy, width, height, flip, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY)) { DBG("%s: blit failure\n", __FUNCTION__); return GL_FALSE; } out: intel_check_front_buffer_rendering(intel); DBG("%s: success\n", __FUNCTION__); return GL_TRUE; }
static void intel_copy_image_sub_data(struct gl_context *ctx, struct gl_texture_image *src_image, struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_image, struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { struct brw_context *brw = brw_context(ctx); struct intel_mipmap_tree *src_mt, *dst_mt; unsigned src_level, dst_level; if (src_image) { src_mt = intel_texture_image(src_image)->mt; src_level = src_image->Level + src_image->TexObject->MinLevel; /* Cube maps actually have different images per face */ if (src_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) src_z = src_image->Face; src_z += src_image->TexObject->MinLayer; } else { assert(src_renderbuffer); src_mt = intel_renderbuffer(src_renderbuffer)->mt; src_image = src_renderbuffer->TexImage; src_level = 0; } if (dst_image) { dst_mt = intel_texture_image(dst_image)->mt; dst_level = dst_image->Level + dst_image->TexObject->MinLevel; /* Cube maps actually have different images per face */ if (dst_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) dst_z = dst_image->Face; dst_z += dst_image->TexObject->MinLayer; } else { assert(dst_renderbuffer); dst_mt = intel_renderbuffer(dst_renderbuffer)->mt; dst_image = dst_renderbuffer->TexImage; dst_level = 0; } copy_miptrees(brw, src_mt, src_x, src_y, src_z, src_level, dst_mt, dst_x, dst_y, dst_z, dst_level, src_width, src_height); /* CopyImage only works for equal formats, texture view equivalence * classes, and a couple special cases for compressed textures. * * Notably, GL_DEPTH_STENCIL does not appear in any equivalence * classes, so we know the formats must be the same, and thus both * will either have stencil, or not. They can't be mismatched. */ assert((src_mt->stencil_mt != NULL) == (dst_mt->stencil_mt != NULL)); if (dst_mt->stencil_mt) { copy_miptrees(brw, src_mt->stencil_mt, src_x, src_y, src_z, src_level, dst_mt->stencil_mt, dst_x, dst_y, dst_z, dst_level, src_width, src_height); } }
/** * Called by glFramebufferTexture[123]DEXT() (and other places) to * prepare for rendering into texture memory. This might be called * many times to choose different texture levels, cube faces, etc * before intel_finish_render_texture() is ever called. */ static void intel_render_texture(GLcontext * ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct gl_texture_image *newImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); struct intel_texture_image *intel_image; GLuint dst_x, dst_y; (void) fb; ASSERT(newImage); intel_image = intel_texture_image(newImage); if (!intel_image->mt) { /* Fallback on drawing to a texture that doesn't have a miptree * (has a border, width/height 0, etc.) */ _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _mesa_render_texture(ctx, fb, att); return; } else if (!irb) { irb = intel_wrap_texture(ctx, newImage); if (irb) { /* bind the wrapper to the attachment point */ _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base); } else { /* fallback to software rendering */ _mesa_render_texture(ctx, fb, att); return; } } if (!intel_update_wrapper(ctx, irb, newImage)) { _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _mesa_render_texture(ctx, fb, att); return; } DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n", _glthread_GetID(), att->Texture->Name, newImage->Width, newImage->Height, irb->Base.RefCount); /* point the renderbufer's region to the texture image region */ if (irb->region != intel_image->mt->region) { if (irb->region) intel_region_release(&irb->region); intel_region_reference(&irb->region, intel_image->mt->region); } /* compute offset of the particular 2D image within the texture region */ intel_miptree_get_image_offset(intel_image->mt, att->TextureLevel, att->CubeMapFace, att->Zoffset, &dst_x, &dst_y); intel_image->mt->region->draw_offset = (dst_y * intel_image->mt->pitch + dst_x) * intel_image->mt->cpp; intel_image->mt->region->draw_x = dst_x; intel_image->mt->region->draw_y = dst_y; intel_image->used_as_render_target = GL_TRUE; /* update drawing region, etc */ intel_draw_buffer(ctx, fb); }
/** * \brief A fast path for glReadPixels * * This fast path is taken when the source format is BGRA, RGBA, * A or L and when the texture memory is X- or Y-tiled. It downloads * the source data by directly mapping the memory without a GTT fence. * This then needs to be de-tiled on the CPU before presenting the data to * the user in the linear fasion. * * This is a performance win over the conventional texture download path. * In the conventional texture download path, the texture is either mapped * through the GTT or copied to a linear buffer with the blitter before * handing off to a software path. This allows us to avoid round-tripping * through the GPU (in the case where we would be blitting) and do only a * single copy operation. */ static bool intel_readpixels_tiled_memcpy(struct gl_context * ctx, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * pixels, const struct gl_pixelstore_attrib *pack) { struct brw_context *brw = brw_context(ctx); struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; const struct gen_device_info *devinfo = &brw->screen->devinfo; /* This path supports reading from color buffers only */ if (rb == NULL) return false; struct intel_renderbuffer *irb = intel_renderbuffer(rb); int dst_pitch; /* The miptree's buffer. */ struct brw_bo *bo; uint32_t cpp; mem_copy_fn mem_copy = NULL; /* This fastpath is restricted to specific renderbuffer types: * a 2D BGRA, RGBA, L8 or A8 texture. It could be generalized to support * more types. */ if (!devinfo->has_llc || !(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) || pixels == NULL || _mesa_is_bufferobj(pack->BufferObj) || pack->Alignment > 4 || pack->SkipPixels > 0 || pack->SkipRows > 0 || (pack->RowLength != 0 && pack->RowLength != width) || pack->SwapBytes || pack->LsbFirst || pack->Invert) return false; /* Only a simple blit, no scale, bias or other mapping. */ if (ctx->_ImageTransferState) return false; /* It is possible that the renderbuffer (or underlying texture) is * multisampled. Since ReadPixels from a multisampled buffer requires a * multisample resolve, we can't handle this here */ if (rb->NumSamples > 1) return false; /* We can't handle copying from RGBX or BGRX because the tiled_memcpy * function doesn't set the last channel to 1. Note this checks BaseFormat * rather than TexFormat in case the RGBX format is being simulated with an * RGBA format. */ if (rb->_BaseFormat == GL_RGB) return false; if (!intel_get_memcpy(rb->Format, format, type, &mem_copy, &cpp)) return false; if (!irb->mt || (irb->mt->surf.tiling != ISL_TILING_X && irb->mt->surf.tiling != ISL_TILING_Y0)) { /* The algorithm is written only for X- or Y-tiled memory. */ return false; } /* tiled_to_linear() assumes that if the object is swizzled, it is using * I915_BIT6_SWIZZLE_9_10 for X and I915_BIT6_SWIZZLE_9 for Y. This is only * true on gen5 and above. * * The killer on top is that some gen4 have an L-shaped swizzle mode, where * parts of the memory aren't swizzled at all. Userspace just can't handle * that. */ if (devinfo->gen < 5 && brw->has_swizzling) return false; /* Since we are going to read raw data to the miptree, we need to resolve * any pending fast color clears before we start. */ intel_miptree_access_raw(brw, irb->mt, irb->mt_level, irb->mt_layer, false); bo = irb->mt->bo; if (brw_batch_references(&brw->batch, bo)) { perf_debug("Flushing before mapping a referenced bo.\n"); intel_batchbuffer_flush(brw); } void *map = brw_bo_map(brw, bo, MAP_READ | MAP_RAW); if (map == NULL) { DBG("%s: failed to map bo\n", __func__); return false; } unsigned slice_offset_x, slice_offset_y; intel_miptree_get_image_offset(irb->mt, irb->mt_level, irb->mt_layer, &slice_offset_x, &slice_offset_y); xoffset += slice_offset_x; yoffset += slice_offset_y; dst_pitch = _mesa_image_row_stride(pack, width, format, type); /* For a window-system renderbuffer, the buffer is actually flipped * vertically, so we need to handle that. Since the detiling function * can only really work in the forwards direction, we have to be a * little creative. First, we compute the Y-offset of the first row of * the renderbuffer (in renderbuffer coordinates). We then match that * with the last row of the client's data. Finally, we give * tiled_to_linear a negative pitch so that it walks through the * client's data backwards as it walks through the renderbufer forwards. */ if (rb->Name == 0) { yoffset = rb->Height - yoffset - height; pixels += (ptrdiff_t) (height - 1) * dst_pitch; dst_pitch = -dst_pitch; } /* We postponed printing this message until having committed to executing * the function. */ DBG("%s: x,y=(%d,%d) (w,h)=(%d,%d) format=0x%x type=0x%x " "mesa_format=0x%x tiling=%d " "pack=(alignment=%d row_length=%d skip_pixels=%d skip_rows=%d)\n", __func__, xoffset, yoffset, width, height, format, type, rb->Format, irb->mt->surf.tiling, pack->Alignment, pack->RowLength, pack->SkipPixels, pack->SkipRows); tiled_to_linear( xoffset * cpp, (xoffset + width) * cpp, yoffset, yoffset + height, pixels - (ptrdiff_t) yoffset * dst_pitch - (ptrdiff_t) xoffset * cpp, map + irb->mt->offset, dst_pitch, irb->mt->surf.row_pitch, brw->has_swizzling, irb->mt->surf.tiling, mem_copy ); brw_bo_unmap(bo); return true; }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct brw_context *brw = brw_context(ctx); struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; DBG("%s() on fb %p (%s)\n", __FUNCTION__, fb, (fb == ctx->DrawBuffer ? "drawbuffer" : (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); if (depthRb) depth_mt = depthRb->mt; if (stencilRb) { stencil_mt = stencilRb->mt; if (stencil_mt->stencil_mt) stencil_mt = stencil_mt->stencil_mt; } if (depth_mt && stencil_mt) { if (brw->gen >= 7) { /* For gen >= 7, we are using the lod/minimum-array-element fields * and supportting layered rendering. This means that we must restrict * the depth & stencil attachments to match in various more retrictive * ways. (width, height, depth, LOD and layer) */ if (depth_mt->physical_width0 != stencil_mt->physical_width0 || depth_mt->physical_height0 != stencil_mt->physical_height0 || depth_mt->physical_depth0 != stencil_mt->physical_depth0 || depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fbo_incomplete(fb, "FBO incomplete: depth and stencil must match in" "width, height, depth, LOD and layer\n"); } } if (depth_mt == stencil_mt) { /* For true packed depth/stencil (not faked on prefers-separate-stencil * hardware) we need to be sure they're the same level/layer, since * we'll be emitting a single packet describing the packed setup. */ if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fbo_incomplete(fb, "FBO incomplete: depth image level/layer %d/%d != " "stencil image %d/%d\n", depthRb->mt_level, depthRb->mt_layer, stencilRb->mt_level, stencilRb->mt_layer); } } else { if (!brw->has_separate_stencil) { fbo_incomplete(fb, "FBO incomplete: separate stencil " "unsupported\n"); } if (stencil_mt->format != MESA_FORMAT_S8) { fbo_incomplete(fb, "FBO incomplete: separate stencil is %s " "instead of S8\n", _mesa_get_format_name(stencil_mt->format)); } if (brw->gen < 7 && !intel_renderbuffer_has_hiz(depthRb)) { /* Before Gen7, separate depth and stencil buffers can be used * only if HiZ is enabled. From the Sandybridge PRM, Volume 2, * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable: * [DevSNB]: This field must be set to the same value (enabled * or disabled) as Hierarchical Depth Buffer Enable. */ fbo_incomplete(fb, "FBO incomplete: separate stencil " "without HiZ\n"); } } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { fbo_incomplete(fb, "FBO incomplete: attachment without " "renderbuffer\n"); continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { if (rb->TexImage->Border) { fbo_incomplete(fb, "FBO incomplete: texture with border\n"); continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { fbo_incomplete(fb, "FBO incomplete: software rendering " "renderbuffer\n"); continue; } if (!brw_render_target_supported(brw, rb)) { fbo_incomplete(fb, "FBO incomplete: Unsupported HW " "texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); } } }
static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, void *image_handle) { struct brw_context *brw = brw_context(ctx); struct intel_renderbuffer *irb; __DRIscreen *screen; __DRIimage *image; screen = brw->intelScreen->driScrnPriv; image = screen->dri2.image->lookupEGLImage(screen, image_handle, screen->loaderPrivate); if (image == NULL) return; if (image->planar_format && image->planar_format->nplanes > 1) { _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(planar buffers are not " "supported as render targets."); return; } /* Buffers originating from outside are for read-only. */ if (image->dma_buf_imported) { _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(dma buffers are read-only)"); return; } /* __DRIimage is opaque to the core so it has to be checked here */ switch (image->format) { case MESA_FORMAT_RGBA8888_REV: _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(unsupported image format"); return; break; default: break; } irb = intel_renderbuffer(rb); intel_miptree_release(&irb->mt); irb->mt = intel_miptree_create_for_bo(brw, image->region->bo, image->format, image->offset, image->region->width, image->region->height, image->region->pitch, image->region->tiling); if (!irb->mt) return; rb->InternalFormat = image->internal_format; rb->Width = image->region->width; rb->Height = image->region->height; rb->Format = image->format; rb->_BaseFormat = _mesa_base_fbo_format(ctx, image->internal_format); rb->NeedsFinishRenderTexture = true; }
static GLboolean do_check_fallback(struct brw_context *brw) { struct intel_context *intel = &brw->intel; GLcontext *ctx = &brw->intel.ctx; GLuint i; if (brw->intel.no_rast) { DBG("FALLBACK: rasterization disabled\n"); return GL_TRUE; } /* _NEW_RENDERMODE */ if (ctx->RenderMode != GL_RENDER) { DBG("FALLBACK: render mode\n"); return GL_TRUE; } /* _NEW_TEXTURE: */ for (i = 0; i < BRW_MAX_TEX_UNIT; i++) { struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; if (texUnit->_ReallyEnabled) { struct intel_texture_object *intelObj = intel_texture_object(texUnit->_Current); struct gl_texture_image *texImage = intelObj->base.Image[0][intelObj->firstLevel]; if (texImage->Border) { DBG("FALLBACK: texture border\n"); return GL_TRUE; } } } /* _NEW_STENCIL */ if (ctx->Stencil._Enabled && (ctx->DrawBuffer->Name == 0 && !brw->intel.hw_stencil)) { DBG("FALLBACK: stencil\n"); return GL_TRUE; } /* _NEW_BUFFERS */ if (IS_965(intel->intelScreen->deviceID) && !IS_G4X(intel->intelScreen->deviceID)) { for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[i]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); /* The original gen4 hardware couldn't set up WM surfaces pointing * at an offset within a tile, which can happen when rendering to * anything but the base level of a texture or the +X face/0 depth. * This was fixed with the 4 Series hardware. * * For these original chips, you would have to make the depth and * color destination surfaces include information on the texture * type, LOD, face, and various limits to use them as a destination. * I would have done this, but there's also a nasty requirement that * the depth and the color surfaces all be of the same LOD, which * may be a worse requirement than this alignment. (Also, we may * want to just demote the texture to untiled, instead). */ if (irb->region && irb->region->tiling != I915_TILING_NONE && (irb->region->draw_offset & 4095)) { DBG("FALLBACK: non-tile-aligned destination for tiled FBO\n"); return GL_TRUE; } } } return GL_FALSE; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ GLboolean intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); rb->NumSamples = quantize_num_samples(intel, rb->NumSamples); ASSERT(rb->Name != 0); switch (internalFormat) { default: /* Use the same format-choice logic as for textures. * Renderbuffers aren't any different from textures for us, * except they're less useful because you can't texture with * them. */ rb->Format = intel->ctx.Driver.ChooseTextureFormat(ctx, internalFormat, GL_NONE, GL_NONE); break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* These aren't actual texture formats, so force them here. */ if (intel->has_separate_stencil) { rb->Format = MESA_FORMAT_S8; } else { assert(!intel->must_use_separate_stencil); rb->Format = MESA_FORMAT_S8_Z24; } break; } rb->Width = width; rb->Height = height; rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); intel_miptree_release(&irb->mt); DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat), _mesa_get_format_name(rb->Format), width, height); if (width == 0 || height == 0) return true; irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format, width, height, rb->NumSamples); if (!irb->mt) return false; if (intel->vtbl.is_hiz_depth_format(intel, rb->Format)) { bool ok = intel_miptree_alloc_hiz(intel, irb->mt, rb->NumSamples); if (!ok) { intel_miptree_release(&irb->mt); return false; } } return true; }
/** * Try to do a glBlitFramebuffer using glCopyTexSubImage2D * We can do this when the dst renderbuffer is actually a texture and * there is no scaling, mirroring or scissoring. * * \return new buffer mask indicating the buffers left to blit using the * normal path. */ static GLbitfield intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { if (mask & GL_COLOR_BUFFER_BIT) { GLint i; const struct gl_framebuffer *drawFb = ctx->DrawBuffer; const struct gl_framebuffer *readFb = ctx->ReadBuffer; const struct gl_renderbuffer_attachment *drawAtt; struct intel_renderbuffer *srcRb = intel_renderbuffer(readFb->_ColorReadBuffer); /* If the source and destination are the same size with no mirroring, * the rectangles are within the size of the texture and there is no * scissor then we can use glCopyTexSubimage2D to implement the blit. * This will end up as a fast hardware blit on some drivers. */ const GLboolean use_intel_copy_texsubimage = srcX0 - srcX1 == dstX0 - dstX1 && srcY0 - srcY1 == dstY0 - dstY1 && srcX1 >= srcX0 && srcY1 >= srcY0 && srcX0 >= 0 && srcX1 <= readFb->Width && srcY0 >= 0 && srcY1 <= readFb->Height && dstX0 >= 0 && dstX1 <= drawFb->Width && dstY0 >= 0 && dstY1 <= drawFb->Height && !ctx->Scissor.Enabled; /* Verify that all the draw buffers can be blitted using * intel_copy_texsubimage(). */ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; if (idx == -1) continue; drawAtt = &drawFb->Attachment[idx]; if (srcRb && drawAtt && drawAtt->Texture && use_intel_copy_texsubimage) continue; else return mask; } /* Blit to all active draw buffers */ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; if (idx == -1) continue; drawAtt = &drawFb->Attachment[idx]; { const struct gl_texture_object *texObj = drawAtt->Texture; const GLuint dstLevel = drawAtt->TextureLevel; const GLenum target = texObj->Target; struct gl_texture_image *texImage = _mesa_select_tex_image(ctx, texObj, target, dstLevel); if (!intel_copy_texsubimage(intel_context(ctx), intel_texture_image(texImage), dstX0, dstY0, srcRb, srcX0, srcY0, srcX1 - srcX0, /* width */ srcY1 - srcY0)) return mask; } } mask &= ~GL_COLOR_BUFFER_BIT; } return mask; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ static GLboolean intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); int cpp; GLuint pitch; ASSERT(rb->Name != 0); switch (internalFormat) { case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: rb->Format = MESA_FORMAT_RGB565; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_RGB: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: rb->Format = MESA_FORMAT_XRGB8888; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: rb->Format = MESA_FORMAT_ARGB8888; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* alloc a depth+stencil buffer */ rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; case GL_DEPTH_COMPONENT16: rb->Format = MESA_FORMAT_Z16; rb->DataType = GL_UNSIGNED_SHORT; break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; default: _mesa_problem(ctx, "Unexpected format in intel_alloc_renderbuffer_storage"); return GL_FALSE; } rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); cpp = _mesa_get_format_bytes(rb->Format); intelFlush(ctx); /* free old region */ if (irb->region) { intel_region_release(&irb->region); } /* allocate new memory region/renderbuffer */ /* Choose a pitch to match hardware requirements: */ pitch = ((cpp * width + 63) & ~63) / cpp; /* alloc hardware renderbuffer */ DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width, height, pitch); irb->region = intel_region_alloc(intel, I915_TILING_NONE, cpp, width, height, pitch, GL_TRUE); if (!irb->region) return GL_FALSE; /* out of memory? */ ASSERT(irb->region->buffer); rb->Width = width; rb->Height = height; return GL_TRUE; }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; DBG("%s() on fb %p (%s)\n", __FUNCTION__, fb, (fb == ctx->DrawBuffer ? "drawbuffer" : (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); if (depthRb) depth_mt = depthRb->mt; if (stencilRb) stencil_mt = stencilRb->mt; if (depth_mt && stencil_mt) { /* Make sure that the depth and stencil buffers are actually the same * slice of the same miptree, since we only support packed * depth/stencil. */ if (depth_mt == stencil_mt) { if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fbo_incomplete(fb, "FBO incomplete: depth image level/layer %d/%d != " "stencil image %d/%d\n", depthRb->mt_level, depthRb->mt_layer, stencilRb->mt_level, stencilRb->mt_layer); } } else { fbo_incomplete(fb, "FBO incomplete: separate stencil unsupported\n"); } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { fbo_incomplete(fb, "FBO incomplete: attachment without " "renderbuffer\n"); continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { if (rb->TexImage->Border) { fbo_incomplete(fb, "FBO incomplete: texture with border\n"); continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { fbo_incomplete(fb, "FBO incomplete: software rendering " "renderbuffer\n"); continue; } if (!intel->vtbl.render_target_supported(intel, rb)) { fbo_incomplete(fb, "FBO incomplete: Unsupported HW " "texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); } } }
static bool do_blit_drawpixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct brw_context *brw = brw_context(ctx); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; drm_intel_bo *src_buffer; DBG("%s\n", __FUNCTION__); if (!intel_check_blit_fragment_ops(ctx, false)) return false; if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) { DBG("%s: fallback due to MRT\n", __FUNCTION__); return false; } struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (!_mesa_format_matches_format_and_type(irb->mt->format, format, type, false)) { DBG("%s: bad format for blit\n", __FUNCTION__); return false; } if (unpack->SwapBytes || unpack->LsbFirst || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: bad packing params\n", __FUNCTION__); return false; } int src_stride = _mesa_image_row_stride(unpack, width, format, type); bool src_flip = false; /* Mesa flips the src_stride for unpack->Invert, but we want our mt to have * a normal src_stride. */ if (unpack->Invert) { src_stride = -src_stride; src_flip = true; } src_offset = (GLintptr)pixels; src_offset += _mesa_image_offset(2, unpack, width, height, format, type, 0, 0, 0); intel_prepare_render(brw); src_buffer = intel_bufferobj_buffer(brw, src, src_offset, width * height * irb->mt->cpp); struct intel_mipmap_tree *pbo_mt = intel_miptree_create_for_bo(brw, src_buffer, irb->mt->format, src_offset, width, height, src_stride, I915_TILING_NONE); if (!pbo_mt) return false; if (!intel_miptree_blit(brw, pbo_mt, 0, 0, 0, 0, src_flip, irb->mt, irb->mt_level, irb->mt_layer, x, y, _mesa_is_winsys_fbo(ctx->DrawBuffer), width, height, GL_COPY)) { DBG("%s: blit failed\n", __FUNCTION__); intel_miptree_release(&pbo_mt); return false; } intel_miptree_release(&pbo_mt); if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += width * height; intel_check_front_buffer_rendering(brw); DBG("%s: success\n", __FUNCTION__); return true; }
/** * Sets up a surface state structure to point at the given region. * While it is only used for the front/back buffer currently, it should be * usable for further buffers when doing ARB_draw_buffer support. */ static void gen6_update_renderbuffer_surface(struct brw_context *brw, struct gl_renderbuffer *rb, bool layered, unsigned int unit) { struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *irb = intel_renderbuffer(rb); struct intel_mipmap_tree *mt = irb->mt; uint32_t *surf; uint32_t format = 0; /* _NEW_BUFFERS */ mesa_format rb_format = _mesa_get_render_format(ctx, intel_rb_format(irb)); uint32_t surftype; int depth = MAX2(irb->layer_count, 1); const GLenum gl_target = rb->TexImage ? rb->TexImage->TexObject->Target : GL_TEXTURE_2D; uint32_t surf_index = brw->wm.prog_data->binding_table.render_target_start + unit; intel_miptree_used_for_rendering(irb->mt); surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE, 6 * 4, 32, &brw->wm.base.surf_offset[surf_index]); format = brw->render_target_format[rb_format]; if (unlikely(!brw->format_supported_as_render_target[rb_format])) { _mesa_problem(ctx, "%s: renderbuffer format %s unsupported\n", __func__, _mesa_get_format_name(rb_format)); } switch (gl_target) { case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_CUBE_MAP: surftype = BRW_SURFACE_2D; depth *= 6; break; case GL_TEXTURE_3D: depth = MAX2(irb->mt->logical_depth0, 1); /* fallthrough */ default: surftype = translate_tex_target(gl_target); break; } const int min_array_element = layered ? 0 : irb->mt_layer; surf[0] = SET_FIELD(surftype, BRW_SURFACE_TYPE) | SET_FIELD(format, BRW_SURFACE_FORMAT); /* reloc */ assert(mt->offset % mt->cpp == 0); surf[1] = mt->bo->offset64 + mt->offset; /* In the gen6 PRM Volume 1 Part 1: Graphics Core, Section 7.18.3.7.1 * (Surface Arrays For all surfaces other than separate stencil buffer): * * "[DevSNB] Errata: Sampler MSAA Qpitch will be 4 greater than the value * calculated in the equation above , for every other odd Surface Height * starting from 1 i.e. 1,5,9,13" * * Since this Qpitch errata only impacts the sampler, we have to adjust the * input for the rendering surface to achieve the same qpitch. For the * affected heights, we increment the height by 1 for the rendering * surface. */ int height0 = irb->mt->logical_height0; if (brw->gen == 6 && irb->mt->num_samples > 1 && (height0 % 4) == 1) height0++; surf[2] = SET_FIELD(mt->logical_width0 - 1, BRW_SURFACE_WIDTH) | SET_FIELD(height0 - 1, BRW_SURFACE_HEIGHT) | SET_FIELD(irb->mt_level - irb->mt->first_level, BRW_SURFACE_LOD); surf[3] = brw_get_surface_tiling_bits(mt->tiling) | SET_FIELD(depth - 1, BRW_SURFACE_DEPTH) | SET_FIELD(mt->pitch - 1, BRW_SURFACE_PITCH); surf[4] = brw_get_surface_num_multisamples(mt->num_samples) | SET_FIELD(min_array_element, BRW_SURFACE_MIN_ARRAY_ELEMENT) | SET_FIELD(depth - 1, BRW_SURFACE_RENDER_TARGET_VIEW_EXTENT); surf[5] = (mt->align_h == 4 ? BRW_SURFACE_VERTICAL_ALIGN_ENABLE : 0); drm_intel_bo_emit_reloc(brw->batch.bo, brw->wm.base.surf_offset[surf_index] + 4, mt->bo, surf[1] - mt->bo->offset64, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); }
/** * Try to do a glBlitFramebuffer using glCopyTexSubImage2D * We can do this when the dst renderbuffer is actually a texture and * there is no scaling, mirroring or scissoring. * * \return new buffer mask indicating the buffers left to blit using the * normal path. */ static GLbitfield intel_blit_framebuffer_with_blitter(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { struct brw_context *brw = brw_context(ctx); /* Sync up the state of window system buffers. We need to do this before * we go looking for the buffers. */ intel_prepare_render(brw); if (mask & GL_COLOR_BUFFER_BIT) { GLint i; const struct gl_framebuffer *drawFb = ctx->DrawBuffer; const struct gl_framebuffer *readFb = ctx->ReadBuffer; struct gl_renderbuffer *src_rb = readFb->_ColorReadBuffer; struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb); if (!src_irb) { perf_debug("glBlitFramebuffer(): missing src renderbuffer. " "Falling back to software rendering.\n"); return mask; } /* If the source and destination are the same size with no mirroring, * the rectangles are within the size of the texture and there is no * scissor, then we can probably use the blit engine. */ if (!(srcX0 - srcX1 == dstX0 - dstX1 && srcY0 - srcY1 == dstY0 - dstY1 && srcX1 >= srcX0 && srcY1 >= srcY0 && srcX0 >= 0 && srcX1 <= readFb->Width && srcY0 >= 0 && srcY1 <= readFb->Height && dstX0 >= 0 && dstX1 <= drawFb->Width && dstY0 >= 0 && dstY1 <= drawFb->Height && !ctx->Scissor.Enabled)) { perf_debug("glBlitFramebuffer(): non-1:1 blit. " "Falling back to software rendering.\n"); return mask; } /* Blit to all active draw buffers. We don't do any pre-checking, * because we assume that copying to MRTs is rare, and failure midway * through copying is even more rare. Even if it was to occur, it's * safe to let meta start the copy over from scratch, because * glBlitFramebuffer completely overwrites the destination pixels, and * results are undefined if any destination pixels have a dependency on * source pixels. */ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { struct gl_renderbuffer *dst_rb = ctx->DrawBuffer->_ColorDrawBuffers[i]; struct intel_renderbuffer *dst_irb = intel_renderbuffer(dst_rb); if (!dst_irb) { perf_debug("glBlitFramebuffer(): missing dst renderbuffer. " "Falling back to software rendering.\n"); return mask; } gl_format src_format = _mesa_get_srgb_format_linear(src_rb->Format); gl_format dst_format = _mesa_get_srgb_format_linear(dst_rb->Format); if (src_format != dst_format) { perf_debug("glBlitFramebuffer(): unsupported blit from %s to %s. " "Falling back to software rendering.\n", _mesa_get_format_name(src_format), _mesa_get_format_name(dst_format)); return mask; } if (!intel_miptree_blit(brw, src_irb->mt, src_irb->mt_level, src_irb->mt_layer, srcX0, srcY0, src_rb->Name == 0, dst_irb->mt, dst_irb->mt_level, dst_irb->mt_layer, dstX0, dstY0, dst_rb->Name == 0, dstX1 - dstX0, dstY1 - dstY0, GL_COPY)) { perf_debug("glBlitFramebuffer(): unknown blit failure. " "Falling back to software rendering.\n"); return mask; } } mask &= ~GL_COLOR_BUFFER_BIT; } return mask; }
static bool do_single_blorp_clear(struct brw_context *brw, struct gl_framebuffer *fb, struct gl_renderbuffer *rb, unsigned buf, bool partial_clear, bool encode_srgb, unsigned layer) { struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *irb = intel_renderbuffer(rb); mesa_format format = irb->mt->format; struct brw_blorp_params params; brw_blorp_params_init(¶ms); if (!encode_srgb && _mesa_get_format_color_encoding(format) == GL_SRGB) format = _mesa_get_srgb_format_linear(format); brw_blorp_surface_info_init(brw, ¶ms.dst, irb->mt, irb->mt_level, layer, format, true); /* Override the surface format according to the context's sRGB rules. */ params.dst.brw_surfaceformat = brw->render_target_format[format]; params.x0 = fb->_Xmin; params.x1 = fb->_Xmax; if (rb->Name != 0) { params.y0 = fb->_Ymin; params.y1 = fb->_Ymax; } else { params.y0 = rb->Height - fb->_Ymax; params.y1 = rb->Height - fb->_Ymin; } memcpy(¶ms.wm_inputs, ctx->Color.ClearColor.f, sizeof(float) * 4); bool use_simd16_replicated_data = true; /* From the SNB PRM (Vol4_Part1): * * "Replicated data (Message Type = 111) is only supported when * accessing tiled memory. Using this Message Type to access linear * (untiled) memory is UNDEFINED." */ if (irb->mt->tiling == I915_TILING_NONE) use_simd16_replicated_data = false; /* Constant color writes ignore everyting in blend and color calculator * state. This is not documented. */ if (set_write_disables(irb, ctx->Color.ColorMask[buf], params.color_write_disable)) use_simd16_replicated_data = false; if (irb->mt->fast_clear_state != INTEL_FAST_CLEAR_STATE_NO_MCS && !partial_clear && use_simd16_replicated_data && brw_is_color_fast_clear_compatible(brw, irb->mt, &ctx->Color.ClearColor)) { memset(¶ms.wm_inputs, 0xff, 4*sizeof(float)); params.fast_clear_op = GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE; brw_get_fast_clear_rect(brw, fb, irb->mt, ¶ms.x0, ¶ms.y0, ¶ms.x1, ¶ms.y1); } else { brw_meta_get_buffer_rect(fb, ¶ms.x0, ¶ms.y0, ¶ms.x1, ¶ms.y1); } brw_blorp_params_get_clear_kernel(brw, ¶ms, use_simd16_replicated_data); const bool is_fast_clear = params.fast_clear_op == GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE; if (is_fast_clear) { /* Record the clear color in the miptree so that it will be * programmed in SURFACE_STATE by later rendering and resolve * operations. */ const bool color_updated = brw_meta_set_fast_clear_color( brw, irb->mt, &ctx->Color.ClearColor); /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the clear * is redundant and can be skipped. */ if (!color_updated && irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR) return true; /* If the MCS buffer hasn't been allocated yet, we need to allocate * it now. */ if (!irb->mt->mcs_mt) { if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) { /* MCS allocation failed--probably this will only happen in * out-of-memory conditions. But in any case, try to recover * by falling back to a non-blorp clear technique. */ return false; } } } const char *clear_type; if (is_fast_clear) clear_type = "fast"; else if (use_simd16_replicated_data) clear_type = "replicated"; else clear_type = "slow"; DBG("%s (%s) to mt %p level %d layer %d\n", __FUNCTION__, clear_type, irb->mt, irb->mt_level, irb->mt_layer); brw_blorp_exec(brw, ¶ms); if (is_fast_clear) { /* Now that the fast clear has occurred, put the buffer in * INTEL_FAST_CLEAR_STATE_CLEAR so that we won't waste time doing * redundant clears. */ irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; } else if (intel_miptree_is_lossless_compressed(brw, irb->mt)) { /* Compressed buffers can be cleared also using normal rep-clear. In * such case they bahave such as if they were drawn using normal 3D * render pipeline, and we simply mark the mcs as dirty. */ assert(partial_clear); irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_UNRESOLVED; } return true; }
/* * Render a bitmap. */ static bool do_blit_bitmap( struct gl_context *ctx, GLint dstx, GLint dsty, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *irb; GLfloat tmpColor[4]; GLubyte ubcolor[4]; GLuint color; GLsizei bitmap_width = width; GLsizei bitmap_height = height; GLint px, py; GLuint stipple[32]; GLint orig_dstx = dstx; GLint orig_dsty = dsty; /* Update draw buffer bounds */ _mesa_update_state(ctx); if (ctx->Depth.Test) { /* The blit path produces incorrect results when depth testing is on. * It seems the blit Z coord is always 1.0 (the far plane) so fragments * will likely be obscured by other, closer geometry. */ return false; } intel_prepare_render(intel); if (fb->_NumColorDrawBuffers != 1) { perf_debug("accelerated glBitmap() only supports rendering to a " "single color buffer\n"); return false; } irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); if (_mesa_is_bufferobj(unpack->BufferObj)) { bitmap = map_pbo(ctx, width, height, unpack, bitmap); if (bitmap == NULL) return true; /* even though this is an error, we're done */ } COPY_4V(tmpColor, ctx->Current.RasterColor); if (_mesa_need_secondary_color(ctx)) { ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor); } UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]); switch (irb->mt->format) { case MESA_FORMAT_B8G8R8A8_UNORM: case MESA_FORMAT_B8G8R8X8_UNORM: color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]); break; case MESA_FORMAT_B5G6R5_UNORM: color = PACK_COLOR_565(ubcolor[0], ubcolor[1], ubcolor[2]); break; default: perf_debug("Unsupported format %s in accelerated glBitmap()\n", _mesa_get_format_name(irb->mt->format)); return false; } if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F)) return false; /* Clip to buffer bounds and scissor. */ if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; dsty = y_flip(fb, dsty, height); #define DY 32 #define DX 32 /* Chop it all into chunks that can be digested by hardware: */ for (py = 0; py < height; py += DY) { for (px = 0; px < width; px += DX) { int h = MIN2(DY, height - py); int w = MIN2(DX, width - px); GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8; GLenum logic_op = ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY; assert(sz <= sizeof(stipple)); memset(stipple, 0, sz); /* May need to adjust this when padding has been introduced in * sz above: * * Have to translate destination coordinates back into source * coordinates. */ int count = get_bitmap_rect(bitmap_width, bitmap_height, unpack, bitmap, -orig_dstx + (dstx + px), -orig_dsty + y_flip(fb, dsty + py, h), w, h, (GLubyte *)stipple, 8, _mesa_is_winsys_fbo(fb)); if (count == 0) continue; if (!intelEmitImmediateColorExpandBlit(intel, irb->mt->cpp, (GLubyte *)stipple, sz, color, irb->mt->region->pitch, irb->mt->region->bo, 0, irb->mt->region->tiling, dstx + px, dsty + py, w, h, logic_op)) { return false; } if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += count; } } out: if (unlikely(INTEL_DEBUG & DEBUG_SYNC)) intel_batchbuffer_flush(intel); if (_mesa_is_bufferobj(unpack->BufferObj)) { /* done with PBO so unmap it now */ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); } intel_check_front_buffer_rendering(intel); return true; }
brw_blorp_clear_params::brw_blorp_clear_params(struct brw_context *brw, struct gl_framebuffer *fb, struct gl_renderbuffer *rb, GLubyte *color_mask, bool partial_clear, unsigned layer) { struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *irb = intel_renderbuffer(rb); dst.set(brw, irb->mt, irb->mt_level, layer, true); /* Override the surface format according to the context's sRGB rules. */ mesa_format format = _mesa_get_render_format(ctx, irb->mt->format); dst.brw_surfaceformat = brw->render_target_format[format]; x0 = fb->_Xmin; x1 = fb->_Xmax; if (rb->Name != 0) { y0 = fb->_Ymin; y1 = fb->_Ymax; } else { y0 = rb->Height - fb->_Ymax; y1 = rb->Height - fb->_Ymin; } float *push_consts = (float *)&wm_push_consts; push_consts[0] = ctx->Color.ClearColor.f[0]; push_consts[1] = ctx->Color.ClearColor.f[1]; push_consts[2] = ctx->Color.ClearColor.f[2]; push_consts[3] = ctx->Color.ClearColor.f[3]; use_wm_prog = true; memset(&wm_prog_key, 0, sizeof(wm_prog_key)); wm_prog_key.use_simd16_replicated_data = true; /* From the SNB PRM (Vol4_Part1): * * "Replicated data (Message Type = 111) is only supported when * accessing tiled memory. Using this Message Type to access linear * (untiled) memory is UNDEFINED." */ if (irb->mt->tiling == I915_TILING_NONE) wm_prog_key.use_simd16_replicated_data = false; /* Constant color writes ignore everyting in blend and color calculator * state. This is not documented. */ for (int i = 0; i < 4; i++) { if (_mesa_format_has_color_component(irb->mt->format, i) && !color_mask[i]) { color_write_disable[i] = true; wm_prog_key.use_simd16_replicated_data = false; } } /* If we can do this as a fast color clear, do so. * * Note that the condition "!partial_clear" means we only try to do full * buffer clears using fast color clear logic. This is necessary because * the fast color clear alignment requirements mean that we typically have * to clear a larger rectangle than (x0, y0) to (x1, y1). Restricting fast * color clears to the full-buffer condition guarantees that the extra * memory locations that get written to are outside the image boundary (and * hence irrelevant). Note that the rectangle alignment requirements are * never larger than the size of a tile, so there is no danger of * overflowing beyond the memory belonging to the region. */ if (irb->mt->fast_clear_state != INTEL_FAST_CLEAR_STATE_NO_MCS && !partial_clear && wm_prog_key.use_simd16_replicated_data && is_color_fast_clear_compatible(brw, format, &ctx->Color.ClearColor)) { memset(push_consts, 0xff, 4*sizeof(float)); fast_clear_op = GEN7_FAST_CLEAR_OP_FAST_CLEAR; /* Figure out what the clear rectangle needs to be aligned to, and how * much it needs to be scaled down. */ unsigned x_align, y_align, x_scaledown, y_scaledown; if (irb->mt->msaa_layout == INTEL_MSAA_LAYOUT_NONE) { /* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render * Target(s)", beneath the "Fast Color Clear" bullet (p327): * * Clear pass must have a clear rectangle that must follow * alignment rules in terms of pixels and lines as shown in the * table below. Further, the clear-rectangle height and width * must be multiple of the following dimensions. If the height * and width of the render target being cleared do not meet these * requirements, an MCS buffer can be created such that it * follows the requirement and covers the RT. * * The alignment size in the table that follows is related to the * alignment size returned by intel_get_non_msrt_mcs_alignment(), but * with X alignment multiplied by 16 and Y alignment multiplied by 32. */ intel_get_non_msrt_mcs_alignment(brw, irb->mt, &x_align, &y_align); x_align *= 16; y_align *= 32; /* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render * Target(s)", beneath the "Fast Color Clear" bullet (p327): * * In order to optimize the performance MCS buffer (when bound to * 1X RT) clear similarly to MCS buffer clear for MSRT case, * clear rect is required to be scaled by the following factors * in the horizontal and vertical directions: * * The X and Y scale down factors in the table that follows are each * equal to half the alignment value computed above. */ x_scaledown = x_align / 2; y_scaledown = y_align / 2; /* From BSpec: 3D-Media-GPGPU Engine > 3D Pipeline > Pixel > Pixel * Backend > MCS Buffer for Render Target(s) [DevIVB+] > Table "Color * Clear of Non-MultiSampled Render Target Restrictions": * * Clear rectangle must be aligned to two times the number of * pixels in the table shown below due to 16x16 hashing across the * slice. */ x_align *= 2; y_align *= 2; } else { /* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render * Target(s)", beneath the "MSAA Compression" bullet (p326): * * Clear pass for this case requires that scaled down primitive * is sent down with upper left co-ordinate to coincide with * actual rectangle being cleared. For MSAA, clear rectangle’s * height and width need to as show in the following table in * terms of (width,height) of the RT. * * MSAA Width of Clear Rect Height of Clear Rect * 4X Ceil(1/8*width) Ceil(1/2*height) * 8X Ceil(1/2*width) Ceil(1/2*height) * * The text "with upper left co-ordinate to coincide with actual * rectangle being cleared" is a little confusing--it seems to imply * that to clear a rectangle from (x,y) to (x+w,y+h), one needs to * feed the pipeline using the rectangle (x,y) to * (x+Ceil(w/N),y+Ceil(h/2)), where N is either 2 or 8 depending on * the number of samples. Experiments indicate that this is not * quite correct; actually, what the hardware appears to do is to * align whatever rectangle is sent down the pipeline to the nearest * multiple of 2x2 blocks, and then scale it up by a factor of N * horizontally and 2 vertically. So the resulting alignment is 4 * vertically and either 4 or 16 horizontally, and the scaledown * factor is 2 vertically and either 2 or 8 horizontally. */ switch (irb->mt->num_samples) { case 4: x_scaledown = 8; break; case 8: x_scaledown = 2; break; default: assert(!"Unexpected sample count for fast clear"); break; } y_scaledown = 2; x_align = x_scaledown * 2; y_align = y_scaledown * 2; } /* Do the alignment and scaledown. */ x0 = ROUND_DOWN_TO(x0, x_align) / x_scaledown; y0 = ROUND_DOWN_TO(y0, y_align) / y_scaledown; x1 = ALIGN(x1, x_align) / x_scaledown; y1 = ALIGN(y1, y_align) / y_scaledown; } }
/** * Called by glFramebufferTexture[123]DEXT() (and other places) to * prepare for rendering into texture memory. This might be called * many times to choose different texture levels, cube faces, etc * before intel_finish_render_texture() is ever called. */ static void intel_render_texture(struct gl_context * ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct intel_context *intel = intel_context(ctx); struct gl_texture_image *image = _mesa_get_attachment_teximage(att); struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); struct intel_texture_image *intel_image = intel_texture_image(image); struct intel_mipmap_tree *mt = intel_image->mt; int layer; (void) fb; if (att->CubeMapFace > 0) { assert(att->Zoffset == 0); layer = att->CubeMapFace; } else { layer = att->Zoffset; } if (!intel_image->mt) { /* Fallback on drawing to a texture that doesn't have a miptree * (has a border, width/height 0, etc.) */ _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _swrast_render_texture(ctx, fb, att); return; } else if (!irb) { intel_miptree_check_level_layer(mt, att->TextureLevel, layer); irb = (struct intel_renderbuffer *)intel_new_renderbuffer(ctx, ~0); if (irb) { /* bind the wrapper to the attachment point */ _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base.Base); } else { /* fallback to software rendering */ _swrast_render_texture(ctx, fb, att); return; } } if (!intel_renderbuffer_update_wrapper(intel, irb, image, layer)) { _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _swrast_render_texture(ctx, fb, att); return; } irb->tex_image = image; DBG("Begin render %s texture tex=%u w=%d h=%d refcount=%d\n", _mesa_get_format_name(image->TexFormat), att->Texture->Name, image->Width, image->Height, irb->Base.Base.RefCount); /* update drawing region, etc */ intel_draw_buffer(ctx); }
bool do_single_blorp_clear(struct brw_context *brw, struct gl_framebuffer *fb, struct gl_renderbuffer *rb, unsigned buf, bool partial_clear, unsigned layer) { struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *irb = intel_renderbuffer(rb); brw_blorp_clear_params params(brw, fb, rb, ctx->Color.ColorMask[buf], partial_clear, layer); bool is_fast_clear = (params.fast_clear_op == GEN7_FAST_CLEAR_OP_FAST_CLEAR); if (is_fast_clear) { /* Record the clear color in the miptree so that it will be * programmed in SURFACE_STATE by later rendering and resolve * operations. */ uint32_t new_color_value = compute_fast_clear_color_bits(&ctx->Color.ClearColor); if (irb->mt->fast_clear_color_value != new_color_value) { irb->mt->fast_clear_color_value = new_color_value; brw->state.dirty.brw |= BRW_NEW_SURFACES; } /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the clear * is redundant and can be skipped. */ if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR) return true; /* If the MCS buffer hasn't been allocated yet, we need to allocate * it now. */ if (!irb->mt->mcs_mt) { if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) { /* MCS allocation failed--probably this will only happen in * out-of-memory conditions. But in any case, try to recover * by falling back to a non-blorp clear technique. */ return false; } brw->state.dirty.brw |= BRW_NEW_SURFACES; } } const char *clear_type; if (is_fast_clear) clear_type = "fast"; else if (params.wm_prog_key.use_simd16_replicated_data) clear_type = "replicated"; else clear_type = "slow"; DBG("%s (%s) to mt %p level %d layer %d\n", __FUNCTION__, clear_type, irb->mt, irb->mt_level, irb->mt_layer); brw_blorp_exec(brw, ¶ms); if (is_fast_clear) { /* Now that the fast clear has occurred, put the buffer in * INTEL_FAST_CLEAR_STATE_CLEAR so that we won't waste time doing * redundant clears. */ irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; } return true; }
/** * Use blitting to clear the renderbuffers named by 'flags'. * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferMask field * since that might include software renderbuffers or renderbuffers * which we're clearing with triangles. * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear */ void intelClearWithBlit(GLcontext *ctx, GLbitfield mask, GLboolean all, GLint cx, GLint cy, GLint cw, GLint ch) { struct intel_context *intel = intel_context( ctx ); GLuint clear_depth; GLbitfield skipBuffers = 0; BATCH_LOCALS; if (INTEL_DEBUG & DEBUG_DRI) _mesa_printf("%s %x\n", __FUNCTION__, mask); /* * Compute values for clearing the buffers. */ clear_depth = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth = (GLuint) (ctx->DrawBuffer->_DepthMax * ctx->Depth.Clear); } if (mask & BUFFER_BIT_STENCIL) { clear_depth |= (ctx->Stencil.Clear & 0xff) << 24; } /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in * the loop below. */ if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) { skipBuffers = BUFFER_BIT_STENCIL; } /* XXX Move this flush/lock into the following conditional? */ intelFlush( &intel->ctx ); LOCK_HARDWARE( intel ); if (intel->numClipRects) { drm_clip_rect_t clear; int i; if (intel->ctx.DrawBuffer->Name == 0) { /* clearing a window */ /* flip top to bottom */ clear.x1 = cx + intel->drawX; clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch; clear.x2 = clear.x1 + cw; clear.y2 = clear.y1 + ch; /* adjust for page flipping */ if ( intel->sarea->pf_current_page == 1 ) { const GLuint tmp = mask; mask &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT); if ( tmp & BUFFER_BIT_FRONT_LEFT ) mask |= BUFFER_BIT_BACK_LEFT; if ( tmp & BUFFER_BIT_BACK_LEFT ) mask |= BUFFER_BIT_FRONT_LEFT; } } else { /* clearing FBO */ ASSERT(intel->numClipRects == 1); ASSERT(intel->pClipRects == &intel->fboRect); clear.x1 = cx; clear.y1 = intel->ctx.DrawBuffer->Height - cy - ch; clear.x2 = clear.y1 + cw; clear.y2 = clear.y1 + ch; /* no change to mask */ } for (i = 0 ; i < intel->numClipRects ; i++) { const drm_clip_rect_t *box = &intel->pClipRects[i]; drm_clip_rect_t b; GLuint buf; GLuint clearMask = mask; /* use copy, since we modify it below */ if (!all) { intel_intersect_cliprects(&b, &clear, box); } else { b = *box; } if (0) _mesa_printf("clear %d,%d..%d,%d, mask %x\n", b.x1, b.y1, b.x2, b.y2, mask); /* Loop over all renderbuffers */ for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) { const GLbitfield bufBit = 1 << buf; if ((clearMask & bufBit) && !(bufBit & skipBuffers)) { /* OK, clear this renderbuffer */ const struct intel_renderbuffer *irb = intel_renderbuffer(ctx->DrawBuffer-> Attachment[buf].Renderbuffer); GLuint clearVal; GLint pitch, cpp; GLuint BR13, CMD; ASSERT(irb); ASSERT(irb->region); pitch = irb->region->pitch; cpp = irb->region->cpp; /* Setup the blit command */ if (cpp == 4) { BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { CMD = XY_COLOR_BLT_CMD; if (clearMask & BUFFER_BIT_DEPTH) CMD |= XY_COLOR_BLT_WRITE_RGB; if (clearMask & BUFFER_BIT_STENCIL) CMD |= XY_COLOR_BLT_WRITE_ALPHA; } else { /* clearing RGBA */ CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB); } } else { ASSERT(cpp == 2 || cpp == 0); BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24); CMD = XY_COLOR_BLT_CMD; } if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { clearVal = clear_depth; } else { clearVal = (cpp == 4) ? intel->ClearColor8888 : intel->ClearColor565; } /* _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n", buf, irb->Base.Name); */ BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); OUT_BATCH( CMD ); OUT_BATCH( BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); OUT_RELOC( irb->region->buffer, DRM_MM_TT|DRM_MM_WRITE, irb->region->draw_offset ); OUT_BATCH( clearVal ); ADVANCE_BATCH(); clearMask &= ~bufBit; /* turn off bit, for faster loop exit */ } } } intel_batchbuffer_flush( intel->batch ); } UNLOCK_HARDWARE( intel ); }
/** * CopyPixels with the blitter. Don't support zooming, pixel transfer, etc. */ static bool do_blit_copypixels(struct gl_context * ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct brw_context *brw = brw_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_framebuffer *read_fb = ctx->ReadBuffer; GLint orig_dstx; GLint orig_dsty; GLint orig_srcx; GLint orig_srcy; struct intel_renderbuffer *draw_irb = NULL; struct intel_renderbuffer *read_irb = NULL; /* Update draw buffer bounds */ _mesa_update_state(ctx); intel_prepare_render(brw); switch (type) { case GL_COLOR: if (fb->_NumColorDrawBuffers != 1) { perf_debug("glCopyPixels() fallback: MRT\n"); return false; } draw_irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); read_irb = intel_renderbuffer(read_fb->_ColorReadBuffer); break; case GL_DEPTH_STENCIL_EXT: draw_irb = intel_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); read_irb = intel_renderbuffer(read_fb->Attachment[BUFFER_DEPTH].Renderbuffer); break; case GL_DEPTH: perf_debug("glCopyPixels() fallback: GL_DEPTH\n"); return false; case GL_STENCIL: perf_debug("glCopyPixels() fallback: GL_STENCIL\n"); return false; default: perf_debug("glCopyPixels(): Unknown type\n"); return false; } if (!draw_irb) { perf_debug("glCopyPixels() fallback: missing draw buffer\n"); return false; } if (!read_irb) { perf_debug("glCopyPixels() fallback: missing read buffer\n"); return false; } if (draw_irb->mt->num_samples > 1 || read_irb->mt->num_samples > 1) { perf_debug("glCopyPixels() fallback: multisampled buffers\n"); return false; } if (ctx->_ImageTransferState) { perf_debug("glCopyPixels(): Unsupported image transfer state\n"); return false; } if (ctx->Depth.Test) { perf_debug("glCopyPixels(): Unsupported depth test state\n"); return false; } if (ctx->Stencil._Enabled) { perf_debug("glCopyPixels(): Unsupported stencil test state\n"); return false; } if (ctx->Fog.Enabled || ctx->Texture._MaxEnabledTexImageUnit != -1 || ctx->FragmentProgram._Enabled) { perf_debug("glCopyPixels(): Unsupported fragment shader state\n"); return false; } if (ctx->Color.AlphaEnabled || ctx->Color.BlendEnabled) { perf_debug("glCopyPixels(): Unsupported blend state\n"); return false; } if (!ctx->Color.ColorMask[0][0] || !ctx->Color.ColorMask[0][1] || !ctx->Color.ColorMask[0][2] || !ctx->Color.ColorMask[0][3]) { perf_debug("glCopyPixels(): Unsupported color mask state\n"); return false; } if (ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F) { perf_debug("glCopyPixles(): Unsupported pixel zoom\n"); return false; } intel_batchbuffer_flush(brw); /* Clip to destination buffer. */ orig_dstx = dstx; orig_dsty = dsty; if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; /* Adjust src coords for our post-clipped destination origin */ srcx += dstx - orig_dstx; srcy += dsty - orig_dsty; /* Clip to source buffer. */ orig_srcx = srcx; orig_srcy = srcy; if (!_mesa_clip_to_region(0, 0, read_fb->Width, read_fb->Height, &srcx, &srcy, &width, &height)) goto out; /* Adjust dst coords for our post-clipped source origin */ dstx += srcx - orig_srcx; dsty += srcy - orig_srcy; if (!intel_miptree_blit(brw, read_irb->mt, read_irb->mt_level, read_irb->mt_layer, srcx, srcy, _mesa_is_winsys_fbo(read_fb), draw_irb->mt, draw_irb->mt_level, draw_irb->mt_layer, dstx, dsty, _mesa_is_winsys_fbo(fb), width, height, (ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY))) { DBG("%s: blit failure\n", __FUNCTION__); return false; } if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += width * height; out: DBG("%s: success\n", __FUNCTION__); return true; }
bool brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb, GLbitfield buffers, bool partial_clear) { struct gl_context *ctx = &brw->ctx; mesa_format format; enum { FAST_CLEAR, REP_CLEAR, PLAIN_CLEAR } clear_type; GLbitfield plain_clear_buffers, meta_save, rep_clear_buffers, fast_clear_buffers; struct rect fast_clear_rect, clear_rect; int layers; fast_clear_buffers = rep_clear_buffers = plain_clear_buffers = 0; /* First we loop through the color draw buffers and determine which ones * can be fast cleared, which ones can use the replicated write and which * ones have to fall back to regular color clear. */ for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); int index = fb->_ColorDrawBufferIndexes[buf]; /* Only clear the buffers present in the provided mask */ if (((1 << index) & buffers) == 0) continue; /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported, * the framebuffer can be complete with some attachments missing. In * this case the _ColorDrawBuffers pointer will be NULL. */ if (rb == NULL) continue; clear_type = FAST_CLEAR; /* We don't have fast clear until gen7. */ if (brw->gen < 7) clear_type = REP_CLEAR; if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_NO_MCS) clear_type = REP_CLEAR; /* We can't do scissored fast clears because of the restrictions on the * fast clear rectangle size. */ if (partial_clear) clear_type = REP_CLEAR; /* Fast clear is only supported for colors where all components are * either 0 or 1. */ format = _mesa_get_render_format(ctx, irb->mt->format); if (!is_color_fast_clear_compatible(brw, format, &ctx->Color.ClearColor)) clear_type = REP_CLEAR; /* From the SNB PRM (Vol4_Part1): * * "Replicated data (Message Type = 111) is only supported when * accessing tiled memory. Using this Message Type to access * linear (untiled) memory is UNDEFINED." */ if (irb->mt->tiling == I915_TILING_NONE) { perf_debug("falling back to plain clear because buffers are untiled\n"); clear_type = PLAIN_CLEAR; } /* Constant color writes ignore everything in blend and color calculator * state. This is not documented. */ GLubyte *color_mask = ctx->Color.ColorMask[buf]; for (int i = 0; i < 4; i++) { if (_mesa_format_has_color_component(irb->mt->format, i) && !color_mask[i]) { perf_debug("falling back to plain clear because of color mask\n"); clear_type = PLAIN_CLEAR; } } /* Allocate the MCS for non MSRT surfaces now if we're doing a fast * clear and we don't have the MCS yet. On failure, fall back to * replicated clear. */ if (clear_type == FAST_CLEAR && irb->mt->mcs_mt == NULL) if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) clear_type = REP_CLEAR; switch (clear_type) { case FAST_CLEAR: irb->mt->fast_clear_color_value = compute_fast_clear_color_bits(&ctx->Color.ClearColor); irb->need_downsample = true; /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the * clear is redundant and can be skipped. Only skip after we've * updated the fast clear color above though. */ if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR) continue; /* Set fast_clear_state to RESOLVED so we don't try resolve them when * we draw, in case the mt is also bound as a texture. */ irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED; irb->need_downsample = true; fast_clear_buffers |= 1 << index; get_fast_clear_rect(brw, fb, irb, &fast_clear_rect); break; case REP_CLEAR: rep_clear_buffers |= 1 << index; get_buffer_rect(brw, fb, irb, &clear_rect); break; case PLAIN_CLEAR: plain_clear_buffers |= 1 << index; get_buffer_rect(brw, fb, irb, &clear_rect); continue; } } if (!(fast_clear_buffers | rep_clear_buffers)) { if (plain_clear_buffers) /* If we only have plain clears, skip the meta save/restore. */ goto out; else /* Nothing left to do. This happens when we hit the redundant fast * clear case above and nothing else. */ return true; } meta_save = MESA_META_ALPHA_TEST | MESA_META_BLEND | MESA_META_DEPTH_TEST | MESA_META_RASTERIZATION | MESA_META_SHADER | MESA_META_STENCIL_TEST | MESA_META_VERTEX | MESA_META_VIEWPORT | MESA_META_CLIP | MESA_META_CLAMP_FRAGMENT_COLOR | MESA_META_MULTISAMPLE | MESA_META_OCCLUSION_QUERY | MESA_META_DRAW_BUFFERS; _mesa_meta_begin(ctx, meta_save); if (!brw_fast_clear_init(brw)) { /* This is going to be hard to recover from, most likely out of memory. * Bail and let meta try and (probably) fail for us. */ plain_clear_buffers = buffers; goto bail_to_meta; } /* Clears never have the color clamped. */ if (ctx->Extensions.ARB_color_buffer_float) _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); _mesa_DepthMask(GL_FALSE); _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); use_rectlist(brw, true); layers = MAX2(1, fb->MaxNumLayers); if (fast_clear_buffers) { _mesa_meta_drawbuffers_from_bitfield(fast_clear_buffers); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE); brw_draw_rectlist(ctx, &fast_clear_rect, layers); set_fast_clear_op(brw, 0); } if (rep_clear_buffers) { _mesa_meta_drawbuffers_from_bitfield(rep_clear_buffers); brw_bind_rep_write_shader(brw, ctx->Color.ClearColor.f); brw_draw_rectlist(ctx, &clear_rect, layers); } /* Now set the mts we cleared to INTEL_FAST_CLEAR_STATE_CLEAR so we'll * resolve them eventually. */ for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); int index = fb->_ColorDrawBufferIndexes[buf]; if ((1 << index) & fast_clear_buffers) irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; } bail_to_meta: /* Dirty _NEW_BUFFERS so we reemit SURFACE_STATE which sets the fast clear * color before resolve and sets irb->mt->fast_clear_state to UNRESOLVED if * we render to it. */ brw->NewGLState |= _NEW_BUFFERS; /* Set the custom state back to normal and dirty the same bits as above */ use_rectlist(brw, false); _mesa_meta_end(ctx); /* From BSpec: Render Target Fast Clear: * * After Render target fast clear, pipe-control with color cache * write-flush must be issued before sending any DRAW commands on that * render target. */ intel_batchbuffer_emit_mi_flush(brw); /* If we had to fall back to plain clear for any buffers, clear those now * by calling into meta. */ out: if (plain_clear_buffers) _mesa_meta_glsl_Clear(&brw->ctx, plain_clear_buffers); return true; }
/** * Map or unmap all the renderbuffers which we may need during * software rendering. * XXX in the future, we could probably convey extra information to * reduce the number of mappings needed. I.e. if doing a glReadPixels * from the depth buffer, we really only need one mapping. * * XXX Rewrite this function someday. * We can probably just loop over all the renderbuffer attachments, * map/unmap all of them, and not worry about the _ColorDrawBuffers * _ColorReadBuffer, _DepthBuffer or _StencilBuffer fields. */ static void intel_map_unmap_buffers(struct intel_context *intel, GLboolean map) { GLcontext *ctx = &intel->ctx; GLuint i, j; struct intel_renderbuffer *irb; /* color draw buffers */ for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { for (j = 0; j < ctx->DrawBuffer->_NumColorDrawBuffers[i]; j++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[i][j]; irb = intel_renderbuffer(rb); if (irb) { /* this is a user-created intel_renderbuffer */ if (irb->region) { if (map) intel_region_map(intel->intelScreen, irb->region); else intel_region_unmap(intel->intelScreen, irb->region); } irb->pfMap = irb->region->map; irb->pfPitch = irb->region->pitch; } } } /* check for render to textures */ for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment + i; struct gl_texture_object *tex = att->Texture; if (tex) { /* render to texture */ ASSERT(att->Renderbuffer); if (map) { struct gl_texture_image *texImg; texImg = tex->Image[att->CubeMapFace][att->TextureLevel]; intel_tex_map_images(intel, intel_texture_object(tex)); } else { intel_tex_unmap_images(intel, intel_texture_object(tex)); } } } /* color read buffers */ irb = intel_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); if (irb && irb->region) { if (map) intel_region_map(intel->intelScreen, irb->region); else intel_region_unmap(intel->intelScreen, irb->region); irb->pfMap = irb->region->map; irb->pfPitch = irb->region->pitch; } /* Account for front/back color page flipping. * The span routines use the pfMap and pfPitch fields which will * swap the front/back region map/pitch if we're page flipped. * Do this after mapping, above, so the map field is valid. */ #if 0 if (map && ctx->DrawBuffer->Name == 0) { struct intel_renderbuffer *irbFront = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_FRONT_LEFT); struct intel_renderbuffer *irbBack = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_BACK_LEFT); if (irbBack) { /* double buffered */ if (intel->sarea->pf_current_page == 0) { irbFront->pfMap = irbFront->region->map; irbFront->pfPitch = irbFront->region->pitch; irbBack->pfMap = irbBack->region->map; irbBack->pfPitch = irbBack->region->pitch; } else { irbFront->pfMap = irbBack->region->map; irbFront->pfPitch = irbBack->region->pitch; irbBack->pfMap = irbFront->region->map; irbBack->pfPitch = irbFront->region->pitch; } } } #endif /* depth buffer (Note wrapper!) */ if (ctx->DrawBuffer->_DepthBuffer) { irb = intel_renderbuffer(ctx->DrawBuffer->_DepthBuffer->Wrapped); if (irb && irb->region && irb->Base.Name != 0) { if (map) { intel_region_map(intel->intelScreen, irb->region); irb->pfMap = irb->region->map; irb->pfPitch = irb->region->pitch; } else { intel_region_unmap(intel->intelScreen, irb->region); irb->pfMap = NULL; irb->pfPitch = 0; } } } /* stencil buffer (Note wrapper!) */ if (ctx->DrawBuffer->_StencilBuffer) { irb = intel_renderbuffer(ctx->DrawBuffer->_StencilBuffer->Wrapped); if (irb && irb->region && irb->Base.Name != 0) { if (map) { intel_region_map(intel->intelScreen, irb->region); irb->pfMap = irb->region->map; irb->pfPitch = irb->region->pitch; } else { intel_region_unmap(intel->intelScreen, irb->region); irb->pfMap = NULL; irb->pfPitch = 0; } } } }