static void intel_update_image_buffers(struct intel_context *intel, __DRIdrawable *drawable) { struct gl_framebuffer *fb = drawable->driverPrivate; __DRIscreen *screen = intel->intelScreen->driScrnPriv; struct intel_renderbuffer *front_rb; struct intel_renderbuffer *back_rb; struct __DRIimageList images; unsigned int format; uint32_t buffer_mask = 0; int ret; front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); if (back_rb) format = intel_rb_format(back_rb); else if (front_rb) format = intel_rb_format(front_rb); else return; if (front_rb && (_mesa_is_front_buffer_drawing(fb) || _mesa_is_front_buffer_reading(fb) || !back_rb)) { buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; } if (back_rb) buffer_mask |= __DRI_IMAGE_BUFFER_BACK; ret = screen->image.loader->getBuffers(drawable, driGLFormatToImageFormat(format), &drawable->dri2.stamp, drawable->loaderPrivate, buffer_mask, &images); if (!ret) return; if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) { drawable->w = images.front->width; drawable->h = images.front->height; intel_update_image_buffer(intel, drawable, front_rb, images.front, __DRI_IMAGE_BUFFER_FRONT); } if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) { drawable->w = images.back->width; drawable->h = images.back->height; intel_update_image_buffer(intel, drawable, back_rb, images.back, __DRI_IMAGE_BUFFER_BACK); } }
uint32_t brw_depthbuffer_format(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *srb; if (!drb && (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) && !srb->mt->stencil_mt && (intel_rb_format(srb) == MESA_FORMAT_S8_Z24 || intel_rb_format(srb) == MESA_FORMAT_Z32_FLOAT_X24S8)) { drb = srb; } if (!drb) return BRW_DEPTHFORMAT_D32_FLOAT; switch (drb->mt->format) { case MESA_FORMAT_Z16: return BRW_DEPTHFORMAT_D16_UNORM; case MESA_FORMAT_Z32_FLOAT: return BRW_DEPTHFORMAT_D32_FLOAT; case MESA_FORMAT_X8_Z24: if (intel->gen >= 6) { return BRW_DEPTHFORMAT_D24_UNORM_X8_UINT; } else { /* Use D24_UNORM_S8, not D24_UNORM_X8. * * D24_UNORM_X8 was not introduced until Gen5. (See the Ironlake PRM, * Volume 2, Part 1, Section 8.4.6 "Depth/Stencil Buffer State", Bits * 3DSTATE_DEPTH_BUFFER.Surface_Format). * * However, on Gen5, D24_UNORM_X8 may be used only if separate * stencil is enabled, and we never enable it. From the Ironlake PRM, * same section as above, Bit 3DSTATE_DEPTH_BUFFER.Separate_Stencil_Buffer_Enable: * If this field is disabled, the Surface Format of the depth * buffer cannot be D24_UNORM_X8_UINT. */ return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT; } case MESA_FORMAT_S8_Z24: return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT; case MESA_FORMAT_Z32_FLOAT_X24S8: return BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT; default: _mesa_problem(ctx, "Unexpected depth format %s\n", _mesa_get_format_name(intel_rb_format(drb))); return BRW_DEPTHFORMAT_D16_UNORM; } }
static void intel_update_image_buffer(struct intel_context *intel, __DRIdrawable *drawable, struct intel_renderbuffer *rb, __DRIimage *buffer, enum __DRIimageBufferMask buffer_type) { struct intel_region *region = buffer->region; if (!rb || !region) return; unsigned num_samples = rb->Base.Base.NumSamples; if (rb->mt && rb->mt->region && rb->mt->region == region) return; intel_miptree_release(&rb->mt); rb->mt = intel_miptree_create_for_image_buffer(intel, buffer_type, intel_rb_format(rb), num_samples, region); }
/** * \brief Assign a DRI buffer's DRM region to a renderbuffer. * * This is called from intel_update_renderbuffers(). * * \par Note: * DRI buffers whose attachment point is DRI2BufferStencil or * DRI2BufferDepthStencil are handled as special cases. * * \param buffer_name is a human readable name, such as "dri2 front buffer", * that is passed to intel_region_alloc_for_handle(). * * \see intel_update_renderbuffers() * \see intel_region_alloc_for_handle() */ static void intel_process_dri2_buffer(struct intel_context *intel, __DRIdrawable *drawable, __DRIbuffer *buffer, struct intel_renderbuffer *rb, const char *buffer_name) { struct intel_region *region = NULL; if (!rb) return; unsigned num_samples = rb->Base.Base.NumSamples; /* We try to avoid closing and reopening the same BO name, because the first * use of a mapping of the buffer involves a bunch of page faulting which is * moderately expensive. */ if (num_samples == 0) { if (rb->mt && rb->mt->region && rb->mt->region->name == buffer->name) return; } else { if (rb->mt && rb->mt->singlesample_mt && rb->mt->singlesample_mt->region && rb->mt->singlesample_mt->region->name == buffer->name) return; } if (unlikely(INTEL_DEBUG & DEBUG_DRI)) { fprintf(stderr, "attaching buffer %d, at %d, cpp %d, pitch %d\n", buffer->name, buffer->attachment, buffer->cpp, buffer->pitch); } intel_miptree_release(&rb->mt); region = intel_region_alloc_for_handle(intel->intelScreen, buffer->cpp, drawable->w, drawable->h, buffer->pitch / buffer->cpp, buffer->name, buffer_name); if (!region) return; rb->mt = intel_miptree_create_for_dri2_buffer(intel, buffer->attachment, intel_rb_format(rb), num_samples, region); intel_region_release(®ion); }
uint32_t brw_depthbuffer_format(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *srb; if (!drb && (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) && !srb->mt->stencil_mt && (intel_rb_format(srb) == MESA_FORMAT_Z24_UNORM_S8_UINT || intel_rb_format(srb) == MESA_FORMAT_Z32_FLOAT_S8X24_UINT)) { drb = srb; } if (!drb) return BRW_DEPTHFORMAT_D32_FLOAT; return brw_depth_format(brw, drb->mt->format); }
/** * Use blitting to clear the renderbuffers named by 'flags'. * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferIndexes 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 */ GLbitfield intelClearWithBlit(struct gl_context *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; GLuint clear_depth_value, clear_depth_mask; GLint cx, cy, cw, ch; GLbitfield fail_mask = 0; BATCH_LOCALS; /* Note: we don't use this function on Gen7+ hardware, so we can safely * ignore fast color clear issues. */ assert(intel->gen < 7); /* * Compute values for clearing the buffers. */ clear_depth_value = 0; clear_depth_mask = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth_value = (GLuint) (fb->_DepthMax * ctx->Depth.Clear); clear_depth_mask = XY_BLT_WRITE_RGB; } if (mask & BUFFER_BIT_STENCIL) { clear_depth_value |= (ctx->Stencil.Clear & 0xff) << 24; clear_depth_mask |= XY_BLT_WRITE_ALPHA; } cx = fb->_Xmin; if (_mesa_is_winsys_fbo(fb)) cy = ctx->DrawBuffer->Height - fb->_Ymax; else cy = fb->_Ymin; cw = fb->_Xmax - fb->_Xmin; ch = fb->_Ymax - fb->_Ymin; if (cw == 0 || ch == 0) return 0; /* Loop over all renderbuffers */ mask &= (1 << BUFFER_COUNT) - 1; while (mask) { GLuint buf = ffs(mask) - 1; bool is_depth_stencil = buf == BUFFER_DEPTH || buf == BUFFER_STENCIL; struct intel_renderbuffer *irb; int x1, y1, x2, y2; uint32_t clear_val; uint32_t BR13, CMD; struct intel_region *region; int pitch, cpp; drm_intel_bo *aper_array[2]; mask &= ~(1 << buf); irb = intel_get_renderbuffer(fb, buf); if (irb && irb->mt) { region = irb->mt->region; assert(region); assert(region->bo); } else { fail_mask |= 1 << buf; continue; } /* OK, clear this renderbuffer */ x1 = cx + irb->draw_x; y1 = cy + irb->draw_y; x2 = cx + cw + irb->draw_x; y2 = cy + ch + irb->draw_y; pitch = region->pitch; cpp = region->cpp; DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n", __FUNCTION__, region->bo, pitch, x1, y1, x2 - x1, y2 - y1); BR13 = 0xf0 << 16; CMD = XY_COLOR_BLT_CMD; /* Setup the blit command */ if (cpp == 4) { if (is_depth_stencil) { CMD |= clear_depth_mask; } else { /* clearing RGBA */ CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; } } assert(region->tiling != I915_TILING_Y); BR13 |= pitch; if (is_depth_stencil) { clear_val = clear_depth_value; } else { uint8_t clear[4]; GLfloat *color = ctx->Color.ClearColor.f; _mesa_unclamped_float_rgba_to_ubyte(clear, color); switch (intel_rb_format(irb)) { case MESA_FORMAT_ARGB8888: case MESA_FORMAT_XRGB8888: clear_val = PACK_COLOR_8888(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_RGB565: clear_val = PACK_COLOR_565(clear[0], clear[1], clear[2]); break; case MESA_FORMAT_ARGB4444: clear_val = PACK_COLOR_4444(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_ARGB1555: clear_val = PACK_COLOR_1555(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_A8: clear_val = PACK_COLOR_8888(clear[3], clear[3], clear[3], clear[3]); break; default: fail_mask |= 1 << buf; continue; } } BR13 |= br13_for_cpp(cpp); assert(x1 < x2); assert(y1 < y2); /* do space check before going any further */ aper_array[0] = intel->batch.bo; aper_array[1] = region->bo; if (drm_intel_bufmgr_check_aperture_space(aper_array, ARRAY_SIZE(aper_array)) != 0) { intel_batchbuffer_flush(intel); } BEGIN_BATCH(6); OUT_BATCH(CMD | (6 - 2)); OUT_BATCH(BR13); OUT_BATCH((y1 << 16) | x1); OUT_BATCH((y2 << 16) | x2); OUT_RELOC_FENCED(region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(clear_val); ADVANCE_BATCH(); if (intel->always_flush_cache) intel_batchbuffer_emit_mi_flush(intel); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) mask &= ~(BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); } return fail_mask; }
static unsigned intel_bits_per_pixel(const struct intel_renderbuffer *rb) { return _mesa_get_format_bytes(intel_rb_format(rb)) * 8; }
/** * 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; } } }
bool intel_copy_texsubimage(struct intel_context *intel, struct intel_texture_image *intelImage, GLint dstx, GLint dsty, struct intel_renderbuffer *irb, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_context *ctx = &intel->ctx; struct intel_region *region; const GLenum internalFormat = intelImage->base.Base.InternalFormat; bool copy_supported = false; bool copy_supported_with_alpha_override = false; intel_prepare_render(intel); if (!intelImage->mt || !irb || !irb->mt) { if (unlikely(INTEL_DEBUG & DEBUG_PERF)) fprintf(stderr, "%s fail %p %p (0x%08x)\n", __FUNCTION__, intelImage->mt, irb, internalFormat); return false; } else { region = irb->mt->region; assert(region); } /* According to the Ivy Bridge PRM, Vol1 Part4, section 1.2.1.2 (Graphics * Data Size Limitations): * * The BLT engine is capable of transferring very large quantities of * graphics data. Any graphics data read from and written to the * destination is permitted to represent a number of pixels that * occupies up to 65,536 scan lines and up to 32,768 bytes per scan line * at the destination. The maximum number of pixels that may be * represented per scan line’s worth of graphics data depends on the * color depth. * * Furthermore, intelEmitCopyBlit (which is called below) uses a signed * 16-bit integer to represent buffer pitch, so it can only handle buffer * pitches < 32k. * * As a result of these two limitations, we can only use the blitter to do * this copy when the region's pitch is less than 32k. */ if (region->pitch >= 32768) return false; if (intelImage->base.Base.TexObject->Target == GL_TEXTURE_1D_ARRAY || intelImage->base.Base.TexObject->Target == GL_TEXTURE_2D_ARRAY) { perf_debug("no support for array textures\n"); } copy_supported = intelImage->base.Base.TexFormat == intel_rb_format(irb); /* Converting ARGB8888 to XRGB8888 is trivial: ignore the alpha bits */ if (intel_rb_format(irb) == MESA_FORMAT_ARGB8888 && intelImage->base.Base.TexFormat == MESA_FORMAT_XRGB8888) { copy_supported = true; } /* Converting XRGB8888 to ARGB8888 requires setting the alpha bits to 1.0 */ if (intel_rb_format(irb) == MESA_FORMAT_XRGB8888 && intelImage->base.Base.TexFormat == MESA_FORMAT_ARGB8888) { copy_supported_with_alpha_override = true; } if (!copy_supported && !copy_supported_with_alpha_override) { if (unlikely(INTEL_DEBUG & DEBUG_PERF)) fprintf(stderr, "%s mismatched formats %s, %s\n", __FUNCTION__, _mesa_get_format_name(intelImage->base.Base.TexFormat), _mesa_get_format_name(intel_rb_format(irb))); return false; } { GLuint image_x, image_y; GLshort src_pitch; /* get dest x/y in destination texture */ intel_miptree_get_image_offset(intelImage->mt, intelImage->base.Base.Level, intelImage->base.Base.Face, &image_x, &image_y); /* The blitter can't handle Y-tiled buffers. */ if (intelImage->mt->region->tiling == I915_TILING_Y) { return false; } if (_mesa_is_winsys_fbo(ctx->ReadBuffer)) { /* Flip vertical orientation for system framebuffers */ y = ctx->ReadBuffer->Height - (y + height); src_pitch = -region->pitch; } else { /* reading from a FBO, y is already oriented the way we like */ src_pitch = region->pitch; } /* blit from src buffer to texture */ if (!intelEmitCopyBlit(intel, intelImage->mt->cpp, src_pitch, region->bo, 0, region->tiling, intelImage->mt->region->pitch, intelImage->mt->region->bo, 0, intelImage->mt->region->tiling, irb->draw_x + x, irb->draw_y + y, image_x + dstx, image_y + dsty, width, height, GL_COPY)) { return false; } } if (copy_supported_with_alpha_override) intel_set_teximage_alpha_to_one(ctx, intelImage); 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); }
/** * 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))); } } }
/** * 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))); } } }
/* * 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 brw_context *brw = brw_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(brw); 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 (_mesa_get_render_format(ctx, intel_rb_format(irb))) { case MESA_FORMAT_ARGB8888: case MESA_FORMAT_XRGB8888: color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]); break; case MESA_FORMAT_RGB565: 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 /* The blitter has no idea about fast color clears, so we need to resolve * the miptree before we do anything. */ intel_miptree_resolve_color(brw, irb->mt); /* 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(brw, 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(brw); if (_mesa_is_bufferobj(unpack->BufferObj)) { /* done with PBO so unmap it now */ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj); } intel_check_front_buffer_rendering(brw); return true; }
bool intel_copy_texsubimage(struct intel_context *intel, struct intel_texture_image *intelImage, GLint dstx, GLint dsty, struct intel_renderbuffer *irb, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_context *ctx = &intel->ctx; struct intel_region *region; const GLenum internalFormat = intelImage->base.Base.InternalFormat; bool copy_supported = false; bool copy_supported_with_alpha_override = false; intel_prepare_render(intel); if (!intelImage->mt || !irb || !irb->mt) { if (unlikely(INTEL_DEBUG & DEBUG_FALLBACKS)) fprintf(stderr, "%s fail %p %p (0x%08x)\n", __FUNCTION__, intelImage->mt, irb, internalFormat); return false; } else { region = irb->mt->region; assert(region); } copy_supported = intelImage->base.Base.TexFormat == intel_rb_format(irb); /* Converting ARGB8888 to XRGB8888 is trivial: ignore the alpha bits */ if (intel_rb_format(irb) == MESA_FORMAT_ARGB8888 && intelImage->base.Base.TexFormat == MESA_FORMAT_XRGB8888) { copy_supported = true; } /* Converting XRGB8888 to ARGB8888 requires setting the alpha bits to 1.0 */ if (intel_rb_format(irb) == MESA_FORMAT_XRGB8888 && intelImage->base.Base.TexFormat == MESA_FORMAT_ARGB8888) { copy_supported_with_alpha_override = true; } if (!copy_supported && !copy_supported_with_alpha_override) { if (unlikely(INTEL_DEBUG & DEBUG_FALLBACKS)) fprintf(stderr, "%s mismatched formats %s, %s\n", __FUNCTION__, _mesa_get_format_name(intelImage->base.Base.TexFormat), _mesa_get_format_name(intel_rb_format(irb))); return false; } { GLuint image_x, image_y; GLshort src_pitch; /* get dest x/y in destination texture */ intel_miptree_get_image_offset(intelImage->mt, intelImage->base.Base.Level, intelImage->base.Base.Face, 0, &image_x, &image_y); /* The blitter can't handle Y-tiled buffers. */ if (intelImage->mt->region->tiling == I915_TILING_Y) { return false; } if (ctx->ReadBuffer->Name == 0) { /* Flip vertical orientation for system framebuffers */ y = ctx->ReadBuffer->Height - (y + height); src_pitch = -region->pitch; } else { /* reading from a FBO, y is already oriented the way we like */ src_pitch = region->pitch; } /* blit from src buffer to texture */ if (!intelEmitCopyBlit(intel, intelImage->mt->cpp, src_pitch, region->bo, 0, region->tiling, intelImage->mt->region->pitch, intelImage->mt->region->bo, 0, intelImage->mt->region->tiling, irb->draw_x + x, irb->draw_y + y, image_x + dstx, image_y + dsty, width, height, GL_COPY)) { return false; } } if (copy_supported_with_alpha_override) intel_set_teximage_alpha_to_one(ctx, intelImage); return true; }
/** * 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 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; bool flip = false; struct intel_renderbuffer *draw_irb = NULL; struct intel_renderbuffer *read_irb = NULL; gl_format read_format, draw_format; /* Update draw buffer bounds */ _mesa_update_state(ctx); 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; } read_format = intel_rb_format(read_irb); draw_format = intel_rb_format(draw_irb); if (draw_format != read_format && !(draw_format == MESA_FORMAT_XRGB8888 && read_format == MESA_FORMAT_ARGB8888)) { perf_debug("glCopyPixels() fallback: mismatched formats (%s -> %s\n", _mesa_get_format_name(read_format), _mesa_get_format_name(draw_format)); return 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 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 (_mesa_is_winsys_fbo(fb)) { /* copypixels to a window system framebuffer */ dsty = fb->Height - dsty - height; flip = !flip; } /* Flip source Y if it's a window system framebuffer. */ if (_mesa_is_winsys_fbo(read_fb)) { 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; uint32_t src_pitch = read_irb->mt->region->pitch; if (flip) src_pitch = -src_pitch; if (!intelEmitCopyBlit(intel, draw_irb->mt->cpp, src_pitch, read_irb->mt->region->bo, 0, read_irb->mt->region->tiling, draw_irb->mt->region->pitch, draw_irb->mt->region->bo, 0, draw_irb->mt->region->tiling, srcx, srcy, dstx, dsty, width, height, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY)) { DBG("%s: blit failure\n", __FUNCTION__); return false; } out: intel_check_front_buffer_rendering(intel); DBG("%s: success\n", __FUNCTION__); return true; }