static bool layout_want_hiz(const struct ilo_layout *layout, const struct ilo_layout_params *params) { const struct pipe_resource *templ = params->templ; const struct util_format_description *desc = util_format_description(templ->format); if (ilo_debug & ILO_DEBUG_NOHIZ) return false; if (!(templ->bind & PIPE_BIND_DEPTH_STENCIL)) return false; if (!util_format_has_depth(desc)) return false; /* no point in having HiZ */ if (templ->usage == PIPE_USAGE_STAGING) return false; /* * As can be seen in layout_calculate_hiz_size(), HiZ may not be enabled * for every level. This is generally fine except on GEN6, where HiZ and * separate stencil are enabled and disabled at the same time. When the * format is PIPE_FORMAT_Z32_FLOAT_S8X24_UINT, enabling and disabling HiZ * can result in incompatible formats. */ if (ilo_dev_gen(params->dev) == ILO_GEN(6) && templ->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT && templ->last_level) return false; return true; }
static void tex_layout_init_hiz(struct tex_layout *layout) { const struct pipe_resource *templ = layout->templ; const struct util_format_description *desc; desc = util_format_description(templ->format); layout->has_depth = util_format_has_depth(desc); layout->has_stencil = util_format_has_stencil(desc); if (!layout->has_depth) return; layout->hiz = true; /* no point in having HiZ */ if (templ->usage & PIPE_USAGE_STAGING) layout->hiz = false; if (layout->dev->gen == ILO_GEN(6)) { /* * From the Sandy Bridge PRM, volume 2 part 1, page 312: * * "The hierarchical depth buffer does not support the LOD field, it * is assumed by hardware to be zero. A separate hierarachical * depth buffer is required for each LOD used, and the * corresponding buffer's state delivered to hardware each time a * new depth buffer state with modified LOD is delivered." * * But we have a stronger requirement. Because of layer offsetting * (check out the callers of ilo_texture_get_slice_offset()), we already * have to require the texture to be non-mipmapped and non-array. */ if (templ->last_level > 0 || templ->array_size > 1 || templ->depth0 > 1) layout->hiz = false; } if (ilo_debug & ILO_DEBUG_NOHIZ) layout->hiz = false; if (layout->has_stencil) { /* * From the Sandy Bridge PRM, volume 2 part 1, page 317: * * "This field (Separate Stencil Buffer Enable) must be set to the * same value (enabled or disabled) as Hierarchical Depth Buffer * Enable." * * GEN7+ requires separate stencil buffers. */ if (layout->dev->gen >= ILO_GEN(7)) layout->separate_stencil = true; else layout->separate_stencil = layout->hiz; if (layout->separate_stencil) layout->has_stencil = false; } }
HRESULT NineBaseTexture9_ctor( struct NineBaseTexture9 *This, struct NineUnknownParams *pParams, struct pipe_resource *initResource, D3DRESOURCETYPE Type, D3DFORMAT format, D3DPOOL Pool, DWORD Usage) { BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !initResource && (format != D3DFMT_NULL); HRESULT hr; DBG("This=%p, pParams=%p initResource=%p Type=%d format=%d Pool=%d Usage=%d\n", This, pParams, initResource, Type, format, Pool, Usage); user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); user_assert(!(Usage & D3DUSAGE_DYNAMIC) || !(Pool == D3DPOOL_MANAGED || Pool == D3DPOOL_SCRATCH), D3DERR_INVALIDCALL); hr = NineResource9_ctor(&This->base, pParams, initResource, alloc, Type, Pool, Usage); if (FAILED(hr)) return hr; This->format = format; This->mipfilter = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? D3DTEXF_LINEAR : D3DTEXF_NONE; This->managed.lod = 0; This->managed.lod_resident = -1; /* Mark the texture as dirty to trigger first upload when we need the texture, * even if it wasn't set by the application */ if (Pool == D3DPOOL_MANAGED) This->managed.dirty = TRUE; /* When a depth buffer is sampled, it is for shadow mapping, except for * D3DFMT_INTZ, D3DFMT_DF16 and D3DFMT_DF24. * In addition D3DFMT_INTZ can be used for both texturing and depth buffering * if z write is disabled. This particular feature may not work for us in * practice because OGL doesn't have that. However apparently it is known * some cards have performance issues with this feature, so real apps * shouldn't use it. */ This->shadow = (This->format != D3DFMT_INTZ && This->format != D3DFMT_DF16 && This->format != D3DFMT_DF24) && util_format_has_depth(util_format_description(This->base.info.format)); This->fetch4_compatible = fetch4_compatible_format(This->format); list_inithead(&This->list); list_inithead(&This->list2); if (Pool == D3DPOOL_MANAGED) list_add(&This->list2, &This->base.base.device->managed_textures); return D3D_OK; }
/* Return whether this is an RGBA, Z, S, or combined ZS format. */ static unsigned get_format_mask(enum pipe_format format) { const struct util_format_description *desc = util_format_description(format); assert(desc); if (util_format_has_depth(desc)) { if (util_format_has_stencil(desc)) { return PIPE_MASK_ZS; } else { return PIPE_MASK_Z; } } else { if (util_format_has_stencil(desc)) { return PIPE_MASK_S; } else { return PIPE_MASK_RGBA; } } }
void lp_build_format_swizzle_soa(const struct util_format_description *format_desc, struct lp_build_context *bld, const LLVMValueRef *unswizzled, LLVMValueRef swizzled_out[4]) { assert(UTIL_FORMAT_SWIZZLE_0 == PIPE_SWIZZLE_ZERO); assert(UTIL_FORMAT_SWIZZLE_1 == PIPE_SWIZZLE_ONE); if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { enum util_format_swizzle swizzle; LLVMValueRef depth_or_stencil; if (util_format_has_stencil(format_desc) && !util_format_has_depth(format_desc)) { assert(!bld->type.floating); swizzle = format_desc->swizzle[1]; } else { assert(bld->type.floating); swizzle = format_desc->swizzle[0]; } /* * Return zzz1 or sss1 for depth-stencil formats here. * Correct swizzling will be handled by apply_sampler_swizzle() later. */ depth_or_stencil = lp_build_swizzle_soa_channel(bld, unswizzled, swizzle); swizzled_out[2] = swizzled_out[1] = swizzled_out[0] = depth_or_stencil; swizzled_out[3] = bld->one; } else { unsigned chan; for (chan = 0; chan < 4; ++chan) { enum util_format_swizzle swizzle = format_desc->swizzle[chan]; swizzled_out[chan] = lp_build_swizzle_soa_channel(bld, unswizzled, swizzle); } } }
static void si_blit_decompress_depth(struct pipe_context *ctx, struct r600_texture *texture, struct r600_texture *staging, unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer, unsigned first_sample, unsigned last_sample) { const struct util_format_description *desc; unsigned planes = 0; assert(staging != NULL && "use si_blit_decompress_zs_in_place instead"); desc = util_format_description(staging->resource.b.b.format); if (util_format_has_depth(desc)) planes |= PIPE_MASK_Z; if (util_format_has_stencil(desc)) planes |= PIPE_MASK_S; si_blit_dbcb_copy( (struct si_context *)ctx, texture, staging, planes, u_bit_consecutive(first_level, last_level - first_level + 1), first_layer, last_layer, first_sample, last_sample); }
static void si_blit_decompress_depth(struct pipe_context *ctx, struct r600_texture *texture, struct r600_texture *staging, unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer, unsigned first_sample, unsigned last_sample) { struct si_context *sctx = (struct si_context *)ctx; unsigned layer, level, sample, checked_last_layer, max_layer; float depth = 1.0f; const struct util_format_description *desc; assert(staging != NULL && "use si_blit_decompress_zs_in_place instead"); desc = util_format_description(staging->resource.b.b.format); if (util_format_has_depth(desc)) sctx->dbcb_depth_copy_enabled = true; if (util_format_has_stencil(desc)) sctx->dbcb_stencil_copy_enabled = true; assert(sctx->dbcb_depth_copy_enabled || sctx->dbcb_stencil_copy_enabled); for (level = first_level; level <= last_level; level++) { /* The smaller the mipmap level, the less layers there are * as far as 3D textures are concerned. */ max_layer = util_max_layer(&texture->resource.b.b, level); checked_last_layer = MIN2(last_layer, max_layer); for (layer = first_layer; layer <= checked_last_layer; layer++) { for (sample = first_sample; sample <= last_sample; sample++) { struct pipe_surface *zsurf, *cbsurf, surf_tmpl; sctx->dbcb_copy_sample = sample; si_mark_atom_dirty(sctx, &sctx->db_render_state); surf_tmpl.format = texture->resource.b.b.format; surf_tmpl.u.tex.level = level; surf_tmpl.u.tex.first_layer = layer; surf_tmpl.u.tex.last_layer = layer; zsurf = ctx->create_surface(ctx, &texture->resource.b.b, &surf_tmpl); surf_tmpl.format = staging->resource.b.b.format; cbsurf = ctx->create_surface(ctx, (struct pipe_resource*)staging, &surf_tmpl); si_blitter_begin(ctx, SI_DECOMPRESS); util_blitter_custom_depth_stencil(sctx->blitter, zsurf, cbsurf, 1 << sample, sctx->custom_dsa_flush, depth); si_blitter_end(ctx); pipe_surface_reference(&zsurf, NULL); pipe_surface_reference(&cbsurf, NULL); } } } sctx->dbcb_depth_copy_enabled = false; sctx->dbcb_stencil_copy_enabled = false; si_mark_atom_dirty(sctx, &sctx->db_render_state); }
static bool swr_texture_layout(struct swr_screen *screen, struct swr_resource *res, boolean allocate) { struct pipe_resource *pt = &res->base; pipe_format fmt = pt->format; const struct util_format_description *desc = util_format_description(fmt); res->has_depth = util_format_has_depth(desc); res->has_stencil = util_format_has_stencil(desc); if (res->has_stencil && !res->has_depth) fmt = PIPE_FORMAT_R8_UINT; /* We always use the SWR layout. For 2D and 3D textures this looks like: * * |<------- pitch ------->| * +=======================+------- * |Array 0 | ^ * | | | * | Level 0 | | * | | | * | | qpitch * +-----------+-----------+ | * | | L2L2L2L2 | | * | Level 1 | L3L3 | | * | | L4 | v * +===========+===========+------- * |Array 1 | * | | * | Level 0 | * | | * | | * +-----------+-----------+ * | | L2L2L2L2 | * | Level 1 | L3L3 | * | | L4 | * +===========+===========+ * * The overall width in bytes is known as the pitch, while the overall * height in rows is the qpitch. Array slices are laid out logically below * one another, qpitch rows apart. For 3D surfaces, the "level" values are * just invalid for the higher array numbers (since depth is also * minified). 1D and 1D array surfaces are stored effectively the same way, * except that pitch never plays into it. All the levels are logically * adjacent to each other on the X axis. The qpitch becomes the number of * elements between array slices, while the pitch is unused. * * Each level's sizes are subject to the valign and halign settings of the * surface. For compressed formats that swr is unaware of, we will use an * appropriately-sized uncompressed format, and scale the widths/heights. * * This surface is stored inside res->swr. For depth/stencil textures, * res->secondary will have an identically-laid-out but R8_UINT-formatted * stencil tree. In the Z32F_S8 case, the primary surface still has 64-bpp * texels, to simplify map/unmap logic which copies the stencil values * in/out. */ res->swr.width = pt->width0; res->swr.height = pt->height0; res->swr.type = swr_convert_target_type(pt->target); res->swr.tileMode = SWR_TILE_NONE; res->swr.format = mesa_to_swr_format(fmt); res->swr.numSamples = std::max(1u, pt->nr_samples); if (pt->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) { res->swr.halign = KNOB_MACROTILE_X_DIM; res->swr.valign = KNOB_MACROTILE_Y_DIM; } else { res->swr.halign = 1; res->swr.valign = 1; } unsigned halign = res->swr.halign * util_format_get_blockwidth(fmt); unsigned width = align(pt->width0, halign); if (pt->target == PIPE_TEXTURE_1D || pt->target == PIPE_TEXTURE_1D_ARRAY) { for (int level = 1; level <= pt->last_level; level++) width += align(u_minify(pt->width0, level), halign); res->swr.pitch = util_format_get_blocksize(fmt); res->swr.qpitch = util_format_get_nblocksx(fmt, width); } else { // The pitch is the overall width of the texture in bytes. Most of the // time this is the pitch of level 0 since all the other levels fit // underneath it. However in some degenerate situations, the width of // level1 + level2 may be larger. In that case, we use those // widths. This can happen if, e.g. halign is 32, and the width of level // 0 is 32 or less. In that case, the aligned levels 1 and 2 will also // be 32 each, adding up to 64. unsigned valign = res->swr.valign * util_format_get_blockheight(fmt); if (pt->last_level > 1) { width = std::max<uint32_t>( width, align(u_minify(pt->width0, 1), halign) + align(u_minify(pt->width0, 2), halign)); } res->swr.pitch = util_format_get_stride(fmt, width); // The qpitch is controlled by either the height of the second LOD, or // the combination of all the later LODs. unsigned height = align(pt->height0, valign); if (pt->last_level == 1) { height += align(u_minify(pt->height0, 1), valign); } else if (pt->last_level > 1) { unsigned level1 = align(u_minify(pt->height0, 1), valign); unsigned level2 = 0; for (int level = 2; level <= pt->last_level; level++) { level2 += align(u_minify(pt->height0, level), valign); } height += std::max(level1, level2); } res->swr.qpitch = util_format_get_nblocksy(fmt, height); } if (pt->target == PIPE_TEXTURE_3D) res->swr.depth = pt->depth0; else res->swr.depth = pt->array_size; // Fix up swr format if necessary so that LOD offset computation works if (res->swr.format == (SWR_FORMAT)-1) { switch (util_format_get_blocksize(fmt)) { default: unreachable("Unexpected format block size"); case 1: res->swr.format = R8_UINT; break; case 2: res->swr.format = R16_UINT; break; case 4: res->swr.format = R32_UINT; break; case 8: if (util_format_is_compressed(fmt)) res->swr.format = BC4_UNORM; else res->swr.format = R32G32_UINT; break; case 16: if (util_format_is_compressed(fmt)) res->swr.format = BC5_UNORM; else res->swr.format = R32G32B32A32_UINT; break; } } for (int level = 0; level <= pt->last_level; level++) { res->mip_offsets[level] = ComputeSurfaceOffset<false>(0, 0, 0, 0, 0, level, &res->swr); } size_t total_size = (size_t)res->swr.depth * res->swr.qpitch * res->swr.pitch; if (total_size > SWR_MAX_TEXTURE_SIZE) return false; if (allocate) { res->swr.pBaseAddress = (uint8_t *)AlignedMalloc(total_size, 64); if (res->has_depth && res->has_stencil) { res->secondary = res->swr; res->secondary.format = R8_UINT; res->secondary.pitch = res->swr.pitch / util_format_get_blocksize(fmt); for (int level = 0; level <= pt->last_level; level++) { res->secondary_mip_offsets[level] = ComputeSurfaceOffset<false>(0, 0, 0, 0, 0, level, &res->secondary); } res->secondary.pBaseAddress = (uint8_t *)AlignedMalloc( res->secondary.depth * res->secondary.qpitch * res->secondary.pitch, 64); } } return true; }
/** * Called via glFlush/glFinish. This is where we copy the contents * of the driver's color buffer into the user-specified buffer. */ static boolean osmesa_st_framebuffer_flush_front(struct st_context_iface *stctx, struct st_framebuffer_iface *stfbi, enum st_attachment_type statt) { OSMesaContext osmesa = OSMesaGetCurrentContext(); struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi); struct pipe_context *pipe = stctx->pipe; struct pipe_resource *res = osbuffer->textures[statt]; struct pipe_transfer *transfer = NULL; struct pipe_box box; void *map; ubyte *src, *dst; unsigned y, bytes, bpp; int dst_stride; if (osmesa->pp) { struct pipe_resource *zsbuf = NULL; unsigned i; /* Find the z/stencil buffer if there is one */ for (i = 0; i < ARRAY_SIZE(osbuffer->textures); i++) { struct pipe_resource *res = osbuffer->textures[i]; if (res) { const struct util_format_description *desc = util_format_description(res->format); if (util_format_has_depth(desc)) { zsbuf = res; break; } } } /* run the postprocess stage(s) */ pp_run(osmesa->pp, res, res, zsbuf); } u_box_2d(0, 0, res->width0, res->height0, &box); map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box, &transfer); /* * Copy the color buffer from the resource to the user's buffer. */ bpp = util_format_get_blocksize(osbuffer->visual.color_format); src = map; dst = osbuffer->map; if (osmesa->user_row_length) dst_stride = bpp * osmesa->user_row_length; else dst_stride = bpp * osbuffer->width; bytes = bpp * res->width0; if (osmesa->y_up) { /* need to flip image upside down */ dst = dst + (res->height0 - 1) * dst_stride; dst_stride = -dst_stride; } for (y = 0; y < res->height0; y++) { memcpy(dst, src, bytes); dst += dst_stride; src += transfer->stride; } pipe->transfer_unmap(pipe, transfer); return TRUE; }
/** * Copy pixel block from src surface to dst surface. * Overlapping regions are acceptable. * Flipping and stretching are supported. * \param filter one of PIPE_TEX_MIPFILTER_NEAREST/LINEAR * \param writemask controls which channels in the dest surface are sourced * from the src surface. Disabled channels are sourced * from (0,0,0,1). */ void util_blit_pixels(struct blit_state *ctx, struct pipe_resource *src_tex, unsigned src_level, int srcX0, int srcY0, int srcX1, int srcY1, int srcZ0, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter, uint writemask, uint zs_writemask) { struct pipe_context *pipe = ctx->pipe; enum pipe_format src_format, dst_format; const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); boolean overlap; boolean is_stencil, is_depth, blit_depth, blit_stencil; const struct util_format_description *src_desc = util_format_description(src_tex->format); struct pipe_blit_info info; assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(src_level <= src_tex->last_level); /* do the regions overlap? */ overlap = src_tex == dst->texture && dst->u.tex.level == src_level && dst->u.tex.first_layer == srcZ0 && regions_overlap(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1); src_format = util_format_linear(src_tex->format); dst_format = util_format_linear(dst->texture->format); /* See whether we will blit depth or stencil. */ is_depth = util_format_has_depth(src_desc); is_stencil = util_format_has_stencil(src_desc); blit_depth = is_depth && (zs_writemask & BLIT_WRITEMASK_Z); blit_stencil = is_stencil && (zs_writemask & BLIT_WRITEMASK_STENCIL); assert((writemask && !zs_writemask && !is_depth && !is_stencil) || (!writemask && (blit_depth || blit_stencil))); /* * XXX: z parameter is deprecated. dst->u.tex.first_layer * specificies the destination layer. */ assert(z == 0.0f); /* * Check for simple case: no format conversion, no flipping, no stretching, * no overlapping, same number of samples. * Filter mode should not matter since there's no stretching. */ if (formats_compatible(src_format, dst_format) && src_tex->nr_samples == dst->texture->nr_samples && is_stencil == blit_stencil && is_depth == blit_depth && srcX0 < srcX1 && dstX0 < dstX1 && srcY0 < srcY1 && dstY0 < dstY1 && (dstX1 - dstX0) == (srcX1 - srcX0) && (dstY1 - dstY0) == (srcY1 - srcY0) && !overlap) { struct pipe_box src_box; src_box.x = srcX0; src_box.y = srcY0; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; pipe->resource_copy_region(pipe, dst->texture, dst->u.tex.level, dstX0, dstY0, dst->u.tex.first_layer,/* dest */ src_tex, src_level, &src_box); return; } memset(&info, 0, sizeof info); info.dst.resource = dst->texture; info.dst.level = dst->u.tex.level; info.dst.box.x = dstX0; info.dst.box.y = dstY0; info.dst.box.z = dst->u.tex.first_layer; info.dst.box.width = dstX1 - dstX0; info.dst.box.height = dstY1 - dstY0; assert(info.dst.box.width >= 0); assert(info.dst.box.height >= 0); info.dst.box.depth = 1; info.dst.format = dst->texture->format; info.src.resource = src_tex; info.src.level = src_level; info.src.box.x = srcX0; info.src.box.y = srcY0; info.src.box.z = srcZ0; info.src.box.width = srcX1 - srcX0; info.src.box.height = srcY1 - srcY0; info.src.box.depth = 1; info.src.format = src_tex->format; info.mask = writemask | (zs_writemask << 4); info.filter = filter; info.scissor_enable = 0; pipe->blit(pipe, &info); }
static boolean swr_texture_layout(struct swr_screen *screen, struct swr_resource *res, boolean allocate) { struct pipe_resource *pt = &res->base; pipe_format fmt = pt->format; const struct util_format_description *desc = util_format_description(fmt); res->has_depth = util_format_has_depth(desc); res->has_stencil = util_format_has_stencil(desc); if (res->has_stencil && !res->has_depth) fmt = PIPE_FORMAT_R8_UINT; res->swr.width = pt->width0; res->swr.height = pt->height0; res->swr.depth = pt->depth0; res->swr.type = swr_convert_target_type(pt->target); res->swr.tileMode = SWR_TILE_NONE; res->swr.format = mesa_to_swr_format(fmt); res->swr.numSamples = (1 << pt->nr_samples); SWR_FORMAT_INFO finfo = GetFormatInfo(res->swr.format); unsigned total_size = 0; unsigned width = pt->width0; unsigned height = pt->height0; unsigned depth = pt->depth0; unsigned layers = pt->array_size; for (int level = 0; level <= pt->last_level; level++) { unsigned alignedWidth, alignedHeight; unsigned num_slices; if (pt->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) { alignedWidth = align(width, KNOB_MACROTILE_X_DIM); alignedHeight = align(height, KNOB_MACROTILE_Y_DIM); } else { alignedWidth = width; alignedHeight = height; } if (level == 0) { res->alignedWidth = alignedWidth; res->alignedHeight = alignedHeight; } res->row_stride[level] = alignedWidth * finfo.Bpp; res->img_stride[level] = res->row_stride[level] * alignedHeight; res->mip_offsets[level] = total_size; if (pt->target == PIPE_TEXTURE_3D) num_slices = depth; else if (pt->target == PIPE_TEXTURE_1D_ARRAY || pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_CUBE || pt->target == PIPE_TEXTURE_CUBE_ARRAY) num_slices = layers; else num_slices = 1; total_size += res->img_stride[level] * num_slices; if (total_size > SWR_MAX_TEXTURE_SIZE) return FALSE; width = u_minify(width, 1); height = u_minify(height, 1); depth = u_minify(depth, 1); } res->swr.halign = res->alignedWidth; res->swr.valign = res->alignedHeight; res->swr.pitch = res->row_stride[0]; if (allocate) { res->swr.pBaseAddress = (uint8_t *)AlignedMalloc(total_size, 64); if (res->has_depth && res->has_stencil) { SWR_FORMAT_INFO finfo = GetFormatInfo(res->secondary.format); res->secondary.width = pt->width0; res->secondary.height = pt->height0; res->secondary.depth = pt->depth0; res->secondary.type = SURFACE_2D; res->secondary.tileMode = SWR_TILE_NONE; res->secondary.format = R8_UINT; res->secondary.numSamples = (1 << pt->nr_samples); res->secondary.pitch = res->alignedWidth * finfo.Bpp; res->secondary.pBaseAddress = (uint8_t *)AlignedMalloc( res->alignedHeight * res->secondary.pitch, 64); } } return TRUE; }
/* Common processing for r600_texture_create and r600_texture_from_handle */ static struct r600_texture * r600_texture_create_object(struct pipe_screen *screen, const struct pipe_resource *base, unsigned pitch_in_bytes_override, struct pb_buffer *buf, struct radeon_surf *surface) { struct r600_texture *rtex; struct r600_resource *resource; struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; rtex = CALLOC_STRUCT(r600_texture); if (rtex == NULL) return NULL; resource = &rtex->resource; resource->b.b = *base; resource->b.vtbl = &r600_texture_vtbl; pipe_reference_init(&resource->b.b.reference, 1); resource->b.b.screen = screen; rtex->pitch_override = pitch_in_bytes_override; /* don't include stencil-only formats which we don't support for rendering */ rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format)); rtex->surface = *surface; if (r600_setup_surface(screen, rtex, pitch_in_bytes_override)) { FREE(rtex); return NULL; } /* Tiled depth textures utilize the non-displayable tile order. * This must be done after r600_setup_surface. * Applies to R600-Cayman. */ rtex->non_disp_tiling = rtex->is_depth && rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D; if (rtex->is_depth) { if (!(base->flags & (R600_RESOURCE_FLAG_TRANSFER | R600_RESOURCE_FLAG_FLUSHED_DEPTH)) && !(rscreen->debug_flags & DBG_NO_HYPERZ)) { r600_texture_allocate_htile(rscreen, rtex); } } else { if (base->nr_samples > 1) { if (!buf) { r600_texture_allocate_fmask(rscreen, rtex); r600_texture_allocate_cmask(rscreen, rtex); rtex->cmask_buffer = &rtex->resource; } if (!rtex->fmask.size || !rtex->cmask.size) { FREE(rtex); return NULL; } } } /* Now create the backing buffer. */ if (!buf) { if (!r600_init_resource(rscreen, resource, rtex->size, rtex->surface.bo_alignment, TRUE)) { FREE(rtex); return NULL; } } else { resource->buf = buf; resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf); resource->gpu_address = rscreen->ws->buffer_get_virtual_address(resource->cs_buf); resource->domains = rscreen->ws->buffer_get_initial_domain(resource->cs_buf); } if (rtex->cmask.size) { /* Initialize the cmask to 0xCC (= compressed state). */ r600_screen_clear_buffer(rscreen, &rtex->cmask_buffer->b.b, rtex->cmask.offset, rtex->cmask.size, 0xCCCCCCCC, true); } /* Initialize the CMASK base register value. */ rtex->cmask.base_address_reg = (rtex->resource.gpu_address + rtex->cmask.offset) >> 8; if (rscreen->debug_flags & DBG_VM) { fprintf(stderr, "VM start=0x%"PRIX64" end=0x%"PRIX64" | Texture %ix%ix%i, %i levels, %i samples, %s\n", rtex->resource.gpu_address, rtex->resource.gpu_address + rtex->resource.buf->size, base->width0, base->height0, util_max_layer(base, 0)+1, base->last_level+1, base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format)); } if (rscreen->debug_flags & DBG_TEX || (rtex->resource.b.b.last_level > 0 && rscreen->debug_flags & DBG_TEXMIP)) { printf("Texture: npix_x=%u, npix_y=%u, npix_z=%u, blk_w=%u, " "blk_h=%u, blk_d=%u, array_size=%u, last_level=%u, " "bpe=%u, nsamples=%u, flags=0x%x, %s\n", rtex->surface.npix_x, rtex->surface.npix_y, rtex->surface.npix_z, rtex->surface.blk_w, rtex->surface.blk_h, rtex->surface.blk_d, rtex->surface.array_size, rtex->surface.last_level, rtex->surface.bpe, rtex->surface.nsamples, rtex->surface.flags, util_format_short_name(base->format)); for (int i = 0; i <= rtex->surface.last_level; i++) { printf(" L %i: offset=%"PRIu64", slice_size=%"PRIu64", npix_x=%u, " "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " "nblk_z=%u, pitch_bytes=%u, mode=%u\n", i, rtex->surface.level[i].offset, rtex->surface.level[i].slice_size, u_minify(rtex->resource.b.b.width0, i), u_minify(rtex->resource.b.b.height0, i), u_minify(rtex->resource.b.b.depth0, i), rtex->surface.level[i].nblk_x, rtex->surface.level[i].nblk_y, rtex->surface.level[i].nblk_z, rtex->surface.level[i].pitch_bytes, rtex->surface.level[i].mode); } if (rtex->surface.flags & RADEON_SURF_SBUFFER) { for (int i = 0; i <= rtex->surface.last_level; i++) { printf(" S %i: offset=%"PRIu64", slice_size=%"PRIu64", npix_x=%u, " "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " "nblk_z=%u, pitch_bytes=%u, mode=%u\n", i, rtex->surface.stencil_level[i].offset, rtex->surface.stencil_level[i].slice_size, u_minify(rtex->resource.b.b.width0, i), u_minify(rtex->resource.b.b.height0, i), u_minify(rtex->resource.b.b.depth0, i), rtex->surface.stencil_level[i].nblk_x, rtex->surface.stencil_level[i].nblk_y, rtex->surface.stencil_level[i].nblk_z, rtex->surface.stencil_level[i].pitch_bytes, rtex->surface.stencil_level[i].mode); } } } return rtex; }
/** * Does format store depth values? */ static inline boolean format_has_depth(enum pipe_format format) { const struct util_format_description *desc = util_format_description(format); return util_format_has_depth(desc); }
static void r600_blit_decompress_depth(struct pipe_context *ctx, struct r600_texture *texture, struct r600_texture *staging, unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer, unsigned first_sample, unsigned last_sample) { struct r600_context *rctx = (struct r600_context *)ctx; unsigned layer, level, sample, checked_last_layer, max_layer, max_sample; struct r600_texture *flushed_depth_texture = staging ? staging : texture->flushed_depth_texture; const struct util_format_description *desc = util_format_description(texture->resource.b.b.format); float depth; if (!staging && !texture->dirty_level_mask) return; max_sample = u_max_sample(&texture->resource.b.b); /* XXX Decompressing MSAA depth textures is broken on R6xx. * There is also a hardlock if CMASK and FMASK are not present. * Just skip this until we find out how to fix it. */ if (rctx->b.chip_class == R600 && max_sample > 0) { texture->dirty_level_mask = 0; return; } if (rctx->b.family == CHIP_RV610 || rctx->b.family == CHIP_RV630 || rctx->b.family == CHIP_RV620 || rctx->b.family == CHIP_RV635) depth = 0.0f; else depth = 1.0f; /* Enable decompression in DB_RENDER_CONTROL */ rctx->db_misc_state.flush_depthstencil_through_cb = true; rctx->db_misc_state.copy_depth = util_format_has_depth(desc); rctx->db_misc_state.copy_stencil = util_format_has_stencil(desc); rctx->db_misc_state.copy_sample = first_sample; rctx->db_misc_state.atom.dirty = true; for (level = first_level; level <= last_level; level++) { if (!staging && !(texture->dirty_level_mask & (1 << level))) continue; /* The smaller the mipmap level, the less layers there are * as far as 3D textures are concerned. */ max_layer = util_max_layer(&texture->resource.b.b, level); checked_last_layer = last_layer < max_layer ? last_layer : max_layer; for (layer = first_layer; layer <= checked_last_layer; layer++) { for (sample = first_sample; sample <= last_sample; sample++) { struct pipe_surface *zsurf, *cbsurf, surf_tmpl; if (sample != rctx->db_misc_state.copy_sample) { rctx->db_misc_state.copy_sample = sample; rctx->db_misc_state.atom.dirty = true; } surf_tmpl.format = texture->resource.b.b.format; surf_tmpl.u.tex.level = level; surf_tmpl.u.tex.first_layer = layer; surf_tmpl.u.tex.last_layer = layer; zsurf = ctx->create_surface(ctx, &texture->resource.b.b, &surf_tmpl); surf_tmpl.format = flushed_depth_texture->resource.b.b.format; cbsurf = ctx->create_surface(ctx, &flushed_depth_texture->resource.b.b, &surf_tmpl); r600_blitter_begin(ctx, R600_DECOMPRESS); util_blitter_custom_depth_stencil(rctx->blitter, zsurf, cbsurf, 1 << sample, rctx->custom_dsa_flush, depth); r600_blitter_end(ctx); pipe_surface_reference(&zsurf, NULL); pipe_surface_reference(&cbsurf, NULL); } } /* The texture will always be dirty if some layers or samples aren't flushed. * I don't think this case occurs often though. */ if (!staging && first_layer == 0 && last_layer == max_layer && first_sample == 0 && last_sample == max_sample) { texture->dirty_level_mask &= ~(1 << level); } } /* reenable compression in DB_RENDER_CONTROL */ rctx->db_misc_state.flush_depthstencil_through_cb = false; rctx->db_misc_state.atom.dirty = true; }
static void si_blit_decompress_depth(struct pipe_context *ctx, struct r600_texture *texture, struct r600_texture *staging, unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer, unsigned first_sample, unsigned last_sample) { struct si_context *sctx = (struct si_context *)ctx; unsigned layer, level, sample, checked_last_layer, max_layer, max_sample; float depth = 1.0f; const struct util_format_description *desc; struct r600_texture *flushed_depth_texture = staging ? staging : texture->flushed_depth_texture; if (!staging && !texture->dirty_level_mask) return; max_sample = u_max_sample(&texture->resource.b.b); desc = util_format_description(flushed_depth_texture->resource.b.b.format); if (util_format_has_depth(desc)) sctx->dbcb_depth_copy_enabled = true; if (util_format_has_stencil(desc)) sctx->dbcb_stencil_copy_enabled = true; assert(sctx->dbcb_depth_copy_enabled || sctx->dbcb_stencil_copy_enabled); for (level = first_level; level <= last_level; level++) { if (!staging && !(texture->dirty_level_mask & (1 << level))) continue; /* The smaller the mipmap level, the less layers there are * as far as 3D textures are concerned. */ max_layer = util_max_layer(&texture->resource.b.b, level); checked_last_layer = last_layer < max_layer ? last_layer : max_layer; for (layer = first_layer; layer <= checked_last_layer; layer++) { for (sample = first_sample; sample <= last_sample; sample++) { struct pipe_surface *zsurf, *cbsurf, surf_tmpl; sctx->dbcb_copy_sample = sample; surf_tmpl.format = texture->resource.b.b.format; surf_tmpl.u.tex.level = level; surf_tmpl.u.tex.first_layer = layer; surf_tmpl.u.tex.last_layer = layer; zsurf = ctx->create_surface(ctx, &texture->resource.b.b, &surf_tmpl); surf_tmpl.format = flushed_depth_texture->resource.b.b.format; cbsurf = ctx->create_surface(ctx, (struct pipe_resource*)flushed_depth_texture, &surf_tmpl); si_blitter_begin(ctx, SI_DECOMPRESS); util_blitter_custom_depth_stencil(sctx->blitter, zsurf, cbsurf, 1 << sample, sctx->custom_dsa_flush, depth); si_blitter_end(ctx); pipe_surface_reference(&zsurf, NULL); pipe_surface_reference(&cbsurf, NULL); } } /* The texture will always be dirty if some layers aren't flushed. * I don't think this case can occur though. */ if (!staging && first_layer == 0 && last_layer == max_layer && first_sample == 0 && last_sample == max_sample) { texture->dirty_level_mask &= ~(1 << level); } } sctx->dbcb_depth_copy_enabled = false; sctx->dbcb_stencil_copy_enabled = false; }
/** * Copy pixel block from src surface to dst surface. * Overlapping regions are acceptable. * Flipping and stretching are supported. * \param filter one of PIPE_TEX_MIPFILTER_NEAREST/LINEAR * \param writemask controls which channels in the dest surface are sourced * from the src surface. Disabled channels are sourced * from (0,0,0,1). */ void util_blit_pixels(struct blit_state *ctx, struct pipe_resource *src_tex, unsigned src_level, int srcX0, int srcY0, int srcX1, int srcY1, int srcZ0, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter, uint writemask, uint zs_writemask) { struct pipe_context *pipe = ctx->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format src_format, dst_format; struct pipe_sampler_view *sampler_view = NULL; struct pipe_sampler_view sv_templ; struct pipe_surface *dst_surface; struct pipe_framebuffer_state fb; const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); unsigned offset; boolean overlap; float s0, t0, s1, t1; boolean normalized; boolean is_stencil, is_depth, blit_depth, blit_stencil; const struct util_format_description *src_desc = util_format_description(src_tex->format); assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(src_level <= src_tex->last_level); /* do the regions overlap? */ overlap = src_tex == dst->texture && dst->u.tex.level == src_level && dst->u.tex.first_layer == srcZ0 && regions_overlap(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1); src_format = util_format_linear(src_tex->format); dst_format = util_format_linear(dst->texture->format); /* See whether we will blit depth or stencil. */ is_depth = util_format_has_depth(src_desc); is_stencil = util_format_has_stencil(src_desc); blit_depth = is_depth && (zs_writemask & BLIT_WRITEMASK_Z); blit_stencil = is_stencil && (zs_writemask & BLIT_WRITEMASK_STENCIL); assert((writemask && !zs_writemask && !is_depth && !is_stencil) || (!writemask && (blit_depth || blit_stencil))); /* * Check for simple case: no format conversion, no flipping, no stretching, * no overlapping, same number of samples. * Filter mode should not matter since there's no stretching. */ if (formats_compatible(src_format, dst_format) && src_tex->nr_samples == dst->texture->nr_samples && is_stencil == blit_stencil && is_depth == blit_depth && srcX0 < srcX1 && dstX0 < dstX1 && srcY0 < srcY1 && dstY0 < dstY1 && (dstX1 - dstX0) == (srcX1 - srcX0) && (dstY1 - dstY0) == (srcY1 - srcY0) && !overlap) { struct pipe_box src_box; src_box.x = srcX0; src_box.y = srcY0; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; pipe->resource_copy_region(pipe, dst->texture, dst->u.tex.level, dstX0, dstY0, dst->u.tex.first_layer,/* dest */ src_tex, src_level, &src_box); return; } /* XXX Reading multisample textures is unimplemented. */ assert(src_tex->nr_samples <= 1); if (src_tex->nr_samples > 1) { return; } /* It's a mistake to call this function with a stencil format and * without shader stencil export. We don't do software fallbacks here. * Ignore stencil and only copy depth. */ if (blit_stencil && !ctx->has_stencil_export) { blit_stencil = FALSE; if (!blit_depth) return; } if (dst_format == dst->format) { dst_surface = dst; } else { struct pipe_surface templ = *dst; templ.format = dst_format; dst_surface = pipe->create_surface(pipe, dst->texture, &templ); } /* Create a temporary texture when src and dest alias. */ if (src_tex == dst_surface->texture && dst_surface->u.tex.level == src_level && dst_surface->u.tex.first_layer == srcZ0) { /* Make a temporary texture which contains a copy of the source pixels. * Then we'll sample from the temporary texture. */ struct pipe_resource texTemp; struct pipe_resource *tex; struct pipe_sampler_view sv_templ; struct pipe_box src_box; const int srcLeft = MIN2(srcX0, srcX1); const int srcTop = MIN2(srcY0, srcY1); if (srcLeft != srcX0) { /* left-right flip */ int tmp = dstX0; dstX0 = dstX1; dstX1 = tmp; } if (srcTop != srcY0) { /* up-down flip */ int tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } /* create temp texture */ memset(&texTemp, 0, sizeof(texTemp)); texTemp.target = ctx->internal_target; texTemp.format = src_format; texTemp.last_level = 0; texTemp.width0 = srcW; texTemp.height0 = srcH; texTemp.depth0 = 1; texTemp.array_size = 1; texTemp.bind = PIPE_BIND_SAMPLER_VIEW; tex = screen->resource_create(screen, &texTemp); if (!tex) return; src_box.x = srcLeft; src_box.y = srcTop; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; /* load temp texture */ pipe->resource_copy_region(pipe, tex, 0, 0, 0, 0, /* dest */ src_tex, src_level, &src_box); normalized = tex->target != PIPE_TEXTURE_RECT; if(normalized) { s0 = 0.0f; s1 = 1.0f; t0 = 0.0f; t1 = 1.0f; } else { s0 = 0; s1 = srcW; t0 = 0; t1 = srcH; } u_sampler_view_default_template(&sv_templ, tex, tex->format); if (!blit_depth && blit_stencil) { /* set a stencil-only format, e.g. Z24S8 --> X24S8 */ sv_templ.format = util_format_stencil_only(tex->format); assert(sv_templ.format != PIPE_FORMAT_NONE); } sampler_view = pipe->create_sampler_view(pipe, tex, &sv_templ); if (!sampler_view) { pipe_resource_reference(&tex, NULL); return; } pipe_resource_reference(&tex, NULL); } else { /* Directly sample from the source resource/texture */ u_sampler_view_default_template(&sv_templ, src_tex, src_format); if (!blit_depth && blit_stencil) { /* set a stencil-only format, e.g. Z24S8 --> X24S8 */ sv_templ.format = util_format_stencil_only(src_format); assert(sv_templ.format != PIPE_FORMAT_NONE); } sampler_view = pipe->create_sampler_view(pipe, src_tex, &sv_templ); if (!sampler_view) { return; } s0 = srcX0; s1 = srcX1; t0 = srcY0; t1 = srcY1; normalized = sampler_view->texture->target != PIPE_TEXTURE_RECT; if(normalized) { s0 /= (float)(u_minify(sampler_view->texture->width0, src_level)); s1 /= (float)(u_minify(sampler_view->texture->width0, src_level)); t0 /= (float)(u_minify(sampler_view->texture->height0, src_level)); t1 /= (float)(u_minify(sampler_view->texture->height0, src_level)); } } assert(screen->is_format_supported(screen, sampler_view->format, ctx->internal_target, sampler_view->texture->nr_samples, PIPE_BIND_SAMPLER_VIEW)); assert(screen->is_format_supported(screen, dst_format, ctx->internal_target, dst_surface->texture->nr_samples, is_depth || is_stencil ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET)); /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); cso_save_rasterizer(ctx->cso); cso_save_sample_mask(ctx->cso); cso_save_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_stream_outputs(ctx->cso); cso_save_viewport(ctx->cso); cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); cso_save_geometry_shader(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_aux_vertex_buffer_slot(ctx->cso); cso_save_render_condition(ctx->cso); /* set misc state we care about */ if (writemask) cso_set_blend(ctx->cso, &ctx->blend_write_color); else cso_set_blend(ctx->cso, &ctx->blend_keep_color); cso_set_sample_mask(ctx->cso, ~0); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); cso_set_stream_outputs(ctx->cso, 0, NULL, 0); cso_set_render_condition(ctx->cso, NULL, 0); /* default sampler state */ ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; ctx->sampler.min_lod = src_level; ctx->sampler.max_lod = src_level; /* Depth stencil state, fragment shader and sampler setup depending on what * we blit. */ if (blit_depth && blit_stencil) { cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); /* don't filter stencil */ ctx->sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_depthstencil); set_depthstencil_fragment_shader(ctx, sampler_view->texture->target); } else if (blit_depth) { cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_depth); set_depth_fragment_shader(ctx, sampler_view->texture->target); } else if (blit_stencil) { /* don't filter stencil */ ctx->sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_stencil); set_stencil_fragment_shader(ctx, sampler_view->texture->target); } else { /* color */ cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_keep_depthstencil); set_fragment_shader(ctx, writemask, sampler_view->texture->target); } cso_single_sampler_done(ctx->cso, PIPE_SHADER_FRAGMENT); /* textures */ if (blit_depth && blit_stencil) { /* Setup two samplers, one for depth and the other one for stencil. */ struct pipe_sampler_view templ; struct pipe_sampler_view *views[2]; templ = *sampler_view; templ.format = util_format_stencil_only(templ.format); assert(templ.format != PIPE_FORMAT_NONE); views[0] = sampler_view; views[1] = pipe->create_sampler_view(pipe, views[0]->texture, &templ); cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 2, views); pipe_sampler_view_reference(&views[1], NULL); } else { cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &sampler_view); } /* viewport */ ctx->viewport.scale[0] = 0.5f * dst_surface->width; ctx->viewport.scale[1] = 0.5f * dst_surface->height; ctx->viewport.scale[2] = 0.5f; ctx->viewport.scale[3] = 1.0f; ctx->viewport.translate[0] = 0.5f * dst_surface->width; ctx->viewport.translate[1] = 0.5f * dst_surface->height; ctx->viewport.translate[2] = 0.5f; ctx->viewport.translate[3] = 0.0f; cso_set_viewport(ctx->cso, &ctx->viewport); set_vertex_shader(ctx); cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); fb.width = dst_surface->width; fb.height = dst_surface->height; if (blit_depth || blit_stencil) { fb.zsbuf = dst_surface; } else { fb.nr_cbufs = 1; fb.cbufs[0] = dst_surface; } cso_set_framebuffer(ctx->cso, &fb); /* draw quad */ offset = setup_vertex_data_tex(ctx, (float) dstX0 / dst_surface->width * 2.0f - 1.0f, (float) dstY0 / dst_surface->height * 2.0f - 1.0f, (float) dstX1 / dst_surface->width * 2.0f - 1.0f, (float) dstY1 / dst_surface->height * 2.0f - 1.0f, s0, t0, s1, t1, z); if (ctx->vbuf) { util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf, cso_get_aux_vertex_buffer_slot(ctx->cso), offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 2); /* attribs/vert */ } /* restore state we changed */ cso_restore_blend(ctx->cso); cso_restore_depth_stencil_alpha(ctx->cso); cso_restore_rasterizer(ctx->cso); cso_restore_sample_mask(ctx->cso); cso_restore_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_viewport(ctx->cso); cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); cso_restore_geometry_shader(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_aux_vertex_buffer_slot(ctx->cso); cso_restore_stream_outputs(ctx->cso); cso_restore_render_condition(ctx->cso); pipe_sampler_view_reference(&sampler_view, NULL); if (dst_surface != dst) pipe_surface_reference(&dst_surface, NULL); }
/* Common processing for r600_texture_create and r600_texture_from_handle */ static struct r600_texture * r600_texture_create_object(struct pipe_screen *screen, const struct pipe_resource *base, unsigned pitch_in_bytes_override, struct pb_buffer *buf, struct radeon_surf *surface) { struct r600_texture *rtex; struct r600_resource *resource; struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; rtex = CALLOC_STRUCT(r600_texture); if (!rtex) return NULL; resource = &rtex->resource; resource->b.b = *base; resource->b.vtbl = &r600_texture_vtbl; pipe_reference_init(&resource->b.b.reference, 1); resource->b.b.screen = screen; /* don't include stencil-only formats which we don't support for rendering */ rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format)); rtex->surface = *surface; if (r600_setup_surface(screen, rtex, pitch_in_bytes_override)) { FREE(rtex); return NULL; } /* Tiled depth textures utilize the non-displayable tile order. * This must be done after r600_setup_surface. * Applies to R600-Cayman. */ rtex->non_disp_tiling = rtex->is_depth && rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D; if (rtex->is_depth) { if (!(base->flags & (R600_RESOURCE_FLAG_TRANSFER | R600_RESOURCE_FLAG_FLUSHED_DEPTH)) && !(rscreen->debug_flags & DBG_NO_HYPERZ)) { r600_texture_allocate_htile(rscreen, rtex); } } else { if (base->nr_samples > 1) { if (!buf) { r600_texture_allocate_fmask(rscreen, rtex); r600_texture_allocate_cmask(rscreen, rtex); rtex->cmask_buffer = &rtex->resource; } if (!rtex->fmask.size || !rtex->cmask.size) { FREE(rtex); return NULL; } } if (rtex->surface.dcc_size) vi_texture_alloc_dcc_separate(rscreen, rtex); } /* Now create the backing buffer. */ if (!buf) { if (!r600_init_resource(rscreen, resource, rtex->size, rtex->surface.bo_alignment, TRUE)) { FREE(rtex); return NULL; } } else { resource->buf = buf; resource->gpu_address = rscreen->ws->buffer_get_virtual_address(resource->buf); resource->domains = rscreen->ws->buffer_get_initial_domain(resource->buf); } if (rtex->cmask.size) { /* Initialize the cmask to 0xCC (= compressed state). */ r600_screen_clear_buffer(rscreen, &rtex->cmask_buffer->b.b, rtex->cmask.offset, rtex->cmask.size, 0xCCCCCCCC, true); } /* Initialize the CMASK base register value. */ rtex->cmask.base_address_reg = (rtex->resource.gpu_address + rtex->cmask.offset) >> 8; if (rscreen->debug_flags & DBG_VM) { fprintf(stderr, "VM start=0x%"PRIX64" end=0x%"PRIX64" | Texture %ix%ix%i, %i levels, %i samples, %s\n", rtex->resource.gpu_address, rtex->resource.gpu_address + rtex->resource.buf->size, base->width0, base->height0, util_max_layer(base, 0)+1, base->last_level+1, base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format)); } if (rscreen->debug_flags & DBG_TEX) { puts("Texture:"); r600_print_texture_info(rtex, stdout); } return rtex; }
static struct r600_resource_texture * r600_texture_create_object(struct pipe_screen *screen, const struct pipe_resource *base, unsigned array_mode, unsigned pitch_in_bytes_override, unsigned max_buffer_size, struct pb_buffer *buf, boolean alloc_bo, struct radeon_surface *surface) { struct r600_resource_texture *rtex; struct si_resource *resource; struct r600_screen *rscreen = (struct r600_screen*)screen; int r; rtex = CALLOC_STRUCT(r600_resource_texture); if (rtex == NULL) return NULL; resource = &rtex->resource; resource->b.b = *base; resource->b.vtbl = &r600_texture_vtbl; pipe_reference_init(&resource->b.b.reference, 1); resource->b.b.screen = screen; rtex->pitch_override = pitch_in_bytes_override; rtex->real_format = base->format; /* don't include stencil-only formats which we don't support for rendering */ rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format)); rtex->surface = *surface; r = r600_setup_surface(screen, rtex, array_mode, pitch_in_bytes_override); if (r) { FREE(rtex); return NULL; } /* Now create the backing buffer. */ if (!buf && alloc_bo) { unsigned base_align = rtex->surface.bo_alignment; unsigned size = rtex->surface.bo_size; base_align = rtex->surface.bo_alignment; if (!si_init_resource(rscreen, resource, size, base_align, FALSE, base->usage)) { FREE(rtex); return NULL; } } else if (buf) { resource->buf = buf; resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf); resource->domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM; } if (debug_get_option_print_texdepth() && rtex->is_depth) { printf("Texture: npix_x=%u, npix_y=%u, npix_z=%u, blk_w=%u, " "blk_h=%u, blk_d=%u, array_size=%u, last_level=%u, " "bpe=%u, nsamples=%u, flags=%u\n", rtex->surface.npix_x, rtex->surface.npix_y, rtex->surface.npix_z, rtex->surface.blk_w, rtex->surface.blk_h, rtex->surface.blk_d, rtex->surface.array_size, rtex->surface.last_level, rtex->surface.bpe, rtex->surface.nsamples, rtex->surface.flags); if (rtex->surface.flags & RADEON_SURF_ZBUFFER) { for (int i = 0; i <= rtex->surface.last_level; i++) { printf(" Z %i: offset=%llu, slice_size=%llu, npix_x=%u, " "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " "nblk_z=%u, pitch_bytes=%u, mode=%u\n", i, rtex->surface.level[i].offset, rtex->surface.level[i].slice_size, rtex->surface.level[i].npix_x, rtex->surface.level[i].npix_y, rtex->surface.level[i].npix_z, rtex->surface.level[i].nblk_x, rtex->surface.level[i].nblk_y, rtex->surface.level[i].nblk_z, rtex->surface.level[i].pitch_bytes, rtex->surface.level[i].mode); } } if (rtex->surface.flags & RADEON_SURF_SBUFFER) { for (int i = 0; i <= rtex->surface.last_level; i++) { printf(" S %i: offset=%llu, slice_size=%llu, npix_x=%u, " "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " "nblk_z=%u, pitch_bytes=%u, mode=%u\n", i, rtex->surface.stencil_level[i].offset, rtex->surface.stencil_level[i].slice_size, rtex->surface.stencil_level[i].npix_x, rtex->surface.stencil_level[i].npix_y, rtex->surface.stencil_level[i].npix_z, rtex->surface.stencil_level[i].nblk_x, rtex->surface.stencil_level[i].nblk_y, rtex->surface.stencil_level[i].nblk_z, rtex->surface.stencil_level[i].pitch_bytes, rtex->surface.stencil_level[i].mode); } } } return rtex; }
void si_blit_uncompress_depth(struct pipe_context *ctx, struct r600_resource_texture *texture, struct r600_resource_texture *staging, unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer) { struct r600_context *rctx = (struct r600_context *)ctx; unsigned layer, level, checked_last_layer, max_layer; float depth = 1.0f; const struct util_format_description *desc; void *custom_dsa; struct r600_resource_texture *flushed_depth_texture = staging ? staging : texture->flushed_depth_texture; if (!staging && !texture->dirty_db_mask) return; desc = util_format_description(flushed_depth_texture->resource.b.b.format); switch (util_format_has_depth(desc) | util_format_has_stencil(desc) << 1) { default: assert(!"No depth or stencil to uncompress"); case 3: custom_dsa = rctx->custom_dsa_flush_depth_stencil; break; case 2: custom_dsa = rctx->custom_dsa_flush_stencil; break; case 1: custom_dsa = rctx->custom_dsa_flush_depth; break; } for (level = first_level; level <= last_level; level++) { if (!staging && !(texture->dirty_db_mask & (1 << level))) continue; /* The smaller the mipmap level, the less layers there are * as far as 3D textures are concerned. */ max_layer = u_max_layer(&texture->resource.b.b, level); checked_last_layer = last_layer < max_layer ? last_layer : max_layer; for (layer = first_layer; layer <= checked_last_layer; layer++) { struct pipe_surface *zsurf, *cbsurf, surf_tmpl; surf_tmpl.format = texture->real_format; surf_tmpl.u.tex.level = level; surf_tmpl.u.tex.first_layer = layer; surf_tmpl.u.tex.last_layer = layer; zsurf = ctx->create_surface(ctx, &texture->resource.b.b, &surf_tmpl); surf_tmpl.format = flushed_depth_texture->real_format; cbsurf = ctx->create_surface(ctx, (struct pipe_resource*)flushed_depth_texture, &surf_tmpl); r600_blitter_begin(ctx, R600_DECOMPRESS); util_blitter_custom_depth_stencil(rctx->blitter, zsurf, cbsurf, ~0, custom_dsa, depth); r600_blitter_end(ctx); pipe_surface_reference(&zsurf, NULL); pipe_surface_reference(&cbsurf, NULL); } /* The texture will always be dirty if some layers aren't flushed. * I don't think this case can occur though. */ if (!staging && first_layer == 0 && last_layer == max_layer) { texture->dirty_db_mask &= ~(1 << level); } } }
static void *virgl_texture_transfer_map(struct pipe_context *ctx, struct pipe_resource *resource, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **transfer) { struct virgl_context *vctx = virgl_context(ctx); struct virgl_screen *vs = virgl_screen(ctx->screen); struct virgl_texture *vtex = virgl_texture(resource); enum pipe_format format = resource->format; struct virgl_transfer *trans; void *ptr; boolean readback = TRUE; uint32_t offset; struct virgl_hw_res *hw_res; const unsigned h = u_minify(vtex->base.u.b.height0, level); const unsigned nblocksy = util_format_get_nblocksy(format, h); bool is_depth = util_format_has_depth(util_format_description(resource->format)); uint32_t l_stride; bool doflushwait; doflushwait = virgl_res_needs_flush_wait(vctx, &vtex->base, usage); if (doflushwait) ctx->flush(ctx, NULL, 0); trans = util_slab_alloc(&vctx->texture_transfer_pool); if (!trans) return NULL; trans->base.resource = resource; trans->base.level = level; trans->base.usage = usage; trans->base.box = *box; trans->base.stride = vtex->stride[level]; trans->base.layer_stride = trans->base.stride * nblocksy; if (resource->target != PIPE_TEXTURE_3D && resource->target != PIPE_TEXTURE_CUBE && resource->target != PIPE_TEXTURE_1D_ARRAY && resource->target != PIPE_TEXTURE_2D_ARRAY && resource->target != PIPE_TEXTURE_CUBE_ARRAY) l_stride = 0; else l_stride = trans->base.layer_stride; if (is_depth && resource->nr_samples > 1) { struct pipe_resource tmp_resource; virgl_init_temp_resource_from_box(&tmp_resource, resource, box, level, 0); trans->resolve_tmp = (struct virgl_resource *)ctx->screen->resource_create(ctx->screen, &tmp_resource); virgl_copy_region_with_blit(ctx, &trans->resolve_tmp->u.b, 0, 0, 0, 0, resource, level, box); ctx->flush(ctx, NULL, 0); /* we want to do a resolve blit into the temporary */ hw_res = trans->resolve_tmp->hw_res; offset = 0; } else { offset = vrend_get_tex_image_offset(vtex, level, box->z); offset += box->y / util_format_get_blockheight(format) * trans->base.stride + box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); hw_res = vtex->base.hw_res; trans->resolve_tmp = NULL; } readback = virgl_res_needs_readback(vctx, &vtex->base, usage); if (readback) vs->vws->transfer_get(vs->vws, hw_res, box, trans->base.stride, l_stride, offset, level); if (doflushwait || readback) vs->vws->resource_wait(vs->vws, vtex->base.hw_res); ptr = vs->vws->resource_map(vs->vws, hw_res); if (!ptr) { return NULL; } trans->offset = offset; *transfer = &trans->base; return ptr + trans->offset; }
static int r600_init_surface(struct r600_common_screen *rscreen, struct radeon_surf *surface, const struct pipe_resource *ptex, unsigned array_mode, bool is_flushed_depth) { const struct util_format_description *desc = util_format_description(ptex->format); bool is_depth, is_stencil; is_depth = util_format_has_depth(desc); is_stencil = util_format_has_stencil(desc); surface->npix_x = ptex->width0; surface->npix_y = ptex->height0; surface->npix_z = ptex->depth0; surface->blk_w = util_format_get_blockwidth(ptex->format); surface->blk_h = util_format_get_blockheight(ptex->format); surface->blk_d = 1; surface->array_size = 1; surface->last_level = ptex->last_level; if (rscreen->chip_class >= EVERGREEN && !is_flushed_depth && ptex->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { surface->bpe = 4; /* stencil is allocated separately on evergreen */ } else { surface->bpe = util_format_get_blocksize(ptex->format); /* align byte per element on dword */ if (surface->bpe == 3) { surface->bpe = 4; } } surface->nsamples = ptex->nr_samples ? ptex->nr_samples : 1; surface->flags = RADEON_SURF_SET(array_mode, MODE); switch (ptex->target) { case PIPE_TEXTURE_1D: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); break; case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_2D: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); break; case PIPE_TEXTURE_3D: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); break; case PIPE_TEXTURE_1D_ARRAY: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); surface->array_size = ptex->array_size; break; case PIPE_TEXTURE_2D_ARRAY: case PIPE_TEXTURE_CUBE_ARRAY: /* cube array layout like 2d array */ surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); surface->array_size = ptex->array_size; break; case PIPE_TEXTURE_CUBE: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE); break; case PIPE_BUFFER: default: return -EINVAL; } if (ptex->bind & PIPE_BIND_SCANOUT) { surface->flags |= RADEON_SURF_SCANOUT; } if (!is_flushed_depth && is_depth) { surface->flags |= RADEON_SURF_ZBUFFER; if (is_stencil) { surface->flags |= RADEON_SURF_SBUFFER | RADEON_SURF_HAS_SBUFFER_MIPTREE; } } if (rscreen->chip_class >= SI) { surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; } return 0; }
static void svga_clear_texture(struct pipe_context *pipe, struct pipe_resource *res, unsigned level, const struct pipe_box *box, const void *data) { struct svga_context *svga = svga_context(pipe); struct svga_surface *svga_surface_dst; enum pipe_error ret; struct pipe_surface tmpl; struct pipe_surface *surface; memset(&tmpl, 0, sizeof(tmpl)); tmpl.format = res->format; tmpl.u.tex.first_layer = box->z; tmpl.u.tex.last_layer = box->z + box->depth - 1; tmpl.u.tex.level = level; surface = pipe->create_surface(pipe, res, &tmpl); if (surface == NULL) { debug_printf("failed to create surface\n"); return; } svga_surface_dst = svga_surface(surface); union pipe_color_union color; const struct util_format_description *desc = util_format_description(surface->format); if (util_format_is_depth_or_stencil(surface->format)) { float depth; uint8_t stencil; unsigned clear_flags = 0; /* If data is NULL, then set depthValue and stencilValue to zeros */ if (data == NULL) { depth = 0.0; stencil = 0; } else { desc->unpack_z_float(&depth, 0, data, 0, 1, 1); desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1); } if (util_format_has_depth(desc)) { clear_flags |= PIPE_CLEAR_DEPTH; } if (util_format_has_stencil(desc)) { clear_flags |= PIPE_CLEAR_STENCIL; } /* Setup depth stencil view */ struct pipe_surface *dsv = svga_validate_surface_view(svga, svga_surface_dst); if (!dsv) { pipe_surface_reference(&surface, NULL); return; } if (box->x == 0 && box->y == 0 && box->width == surface->width && box->height == surface->height) { /* clearing whole surface, use direct VGPU10 command */ ret = SVGA3D_vgpu10_ClearDepthStencilView(svga->swc, dsv, clear_flags, stencil, depth); if (ret != PIPE_OK) { /* flush and try again */ svga_context_flush(svga, NULL); ret = SVGA3D_vgpu10_ClearDepthStencilView(svga->swc, dsv, clear_flags, stencil, depth); assert(ret == PIPE_OK); } } else { /* To clear subtexture use software fallback */ util_blitter_save_framebuffer(svga->blitter, &svga->curr.framebuffer); begin_blit(svga); util_blitter_clear_depth_stencil(svga->blitter, dsv, clear_flags, depth,stencil, box->x, box->y, box->width, box->height); } } else { /* non depth-stencil formats */ if (data == NULL) { /* If data is NULL, the texture image is filled with zeros */ color.f[0] = color.f[1] = color.f[2] = color.f[3] = 0; } else { if (util_format_is_pure_sint(surface->format)) { /* signed integer */ desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1); } else if (util_format_is_pure_uint(surface->format)) { /* unsigned integer */ desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1); } else { /* floating point */ desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1); } } /* Setup render target view */ struct pipe_surface *rtv = svga_validate_surface_view(svga, svga_surface_dst); if (!rtv) { pipe_surface_reference(&surface, NULL); return; } if (box->x == 0 && box->y == 0 && box->width == surface->width && box->height == surface->height) { struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; if (is_integer_target(curr, PIPE_CLEAR_COLOR) && !ints_fit_in_floats(&color)) { /* To clear full texture with integer format */ clear_buffers_with_quad(svga, PIPE_CLEAR_COLOR, &color, 0.0, 0); } else { /* clearing whole surface using VGPU10 command */ ret = SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, rtv, color.f); if (ret != PIPE_OK) { svga_context_flush(svga,NULL); ret = SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, rtv, color.f); assert(ret == PIPE_OK); } } } else { /* To clear subtexture use software fallback */ /** * util_blitter_clear_render_target doesn't support PIPE_TEXTURE_3D * It tries to draw quad with depth 0 for PIPE_TEXTURE_3D so use * util_clear_render_target() for PIPE_TEXTURE_3D. */ if (rtv->texture->target != PIPE_TEXTURE_3D && pipe->screen->is_format_supported(pipe->screen, rtv->format, rtv->texture->target, rtv->texture->nr_samples, PIPE_BIND_RENDER_TARGET)) { /* clear with quad drawing */ util_blitter_save_framebuffer(svga->blitter, &svga->curr.framebuffer); begin_blit(svga); util_blitter_clear_render_target(svga->blitter, rtv, &color, box->x, box->y, box->width, box->height); } else { /* clear with map/write/unmap */ /* store layer values */ unsigned first_layer = rtv->u.tex.first_layer; unsigned last_layer = rtv->u.tex.last_layer; unsigned box_depth = last_layer - first_layer + 1; for (unsigned i = 0; i < box_depth; i++) { rtv->u.tex.first_layer = rtv->u.tex.last_layer = first_layer + i; util_clear_render_target(pipe, rtv, &color, box->x, box->y, box->width, box->height); } /* restore layer values */ rtv->u.tex.first_layer = first_layer; rtv->u.tex.last_layer = last_layer; } } } pipe_surface_reference(&surface, NULL); }