+ struct si_texture *tex;
+ struct si_resource *resource;
+ struct si_screen *sscreen = (struct si_screen *)screen;
+
+ tex = CALLOC_STRUCT(si_texture);
+ if (!tex)
+ goto error;
+
+ resource = &tex->buffer;
+ resource->b.b = *base;
+ resource->b.vtbl = &si_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 */
+ tex->is_depth = util_format_has_depth(util_format_description(tex->buffer.b.b.format));
+ tex->surface = *surface;
+
+ /* On GFX8, HTILE uses different tiling depending on the TC_COMPATIBLE_HTILE
+ * setting, so we have to enable it if we enabled it at allocation.
+ *
+ * GFX9 and later use the same tiling for both, so TC-compatible HTILE can be
+ * enabled on demand.
+ */
+ tex->tc_compatible_htile = sscreen->info.chip_class == GFX8 &&
+ tex->surface.flags & RADEON_SURF_TC_COMPATIBLE_HTILE;
+
+ /* TC-compatible HTILE:
+ * - GFX8 only supports Z32_FLOAT.
+ * - GFX9 only supports Z32_FLOAT and Z16_UNORM. */
+ if (tex->surface.flags & RADEON_SURF_TC_COMPATIBLE_HTILE) {
+ if (sscreen->info.chip_class >= GFX9 && base->format == PIPE_FORMAT_Z16_UNORM)
+ tex->db_render_format = base->format;
+ else {
+ tex->db_render_format = PIPE_FORMAT_Z32_FLOAT;
+ tex->upgraded_depth = base->format != PIPE_FORMAT_Z32_FLOAT &&
+ base->format != PIPE_FORMAT_Z32_FLOAT_S8X24_UINT;
+ }
+ } else {
+ tex->db_render_format = base->format;
+ }
+
+ /* Applies to GCN. */
+ tex->last_msaa_resolve_target_micro_mode = tex->surface.micro_tile_mode;
+
+ /* Disable separate DCC at the beginning. DRI2 doesn't reuse buffers
+ * between frames, so the only thing that can enable separate DCC
+ * with DRI2 is multiple slow clears within a frame.
+ */
+ tex->ps_draw_ratio = 0;
+
+ ac_surface_override_offset_stride(&sscreen->info, &tex->surface,
+ tex->buffer.b.b.last_level + 1,
+ offset, pitch_in_bytes / tex->surface.bpe);
+
+ if (tex->is_depth) {
+ if (sscreen->info.chip_class >= GFX9) {
+ tex->can_sample_z = true;
+ tex->can_sample_s = true;
+
+ /* Stencil texturing with HTILE doesn't work
+ * with mipmapping on Navi10-14. */
+ if (sscreen->info.chip_class == GFX10 && base->last_level > 0)
+ tex->htile_stencil_disabled = true;
+ } else {
+ tex->can_sample_z = !tex->surface.u.legacy.depth_adjusted;
+ tex->can_sample_s = !tex->surface.u.legacy.stencil_adjusted;
+ }
+
+ tex->db_compatible = surface->flags & RADEON_SURF_ZBUFFER;
+ } else {
+ if (tex->surface.cmask_offset) {
+ tex->cb_color_info |= S_028C70_FAST_CLEAR(1);
+ tex->cmask_buffer = &tex->buffer;
+ }
+ }
+
+ if (plane0) {
+ /* The buffer is shared with the first plane. */
+ resource->bo_size = plane0->buffer.bo_size;
+ resource->bo_alignment = plane0->buffer.bo_alignment;
+ resource->flags = plane0->buffer.flags;
+ resource->domains = plane0->buffer.domains;
+ resource->vram_usage = plane0->buffer.vram_usage;
+ resource->gart_usage = plane0->buffer.gart_usage;
+
+ pb_reference(&resource->buf, plane0->buffer.buf);
+ resource->gpu_address = plane0->buffer.gpu_address;
+ } else if (!(surface->flags & RADEON_SURF_IMPORTED)) {
+ /* Create the backing buffer. */
+ si_init_resource_fields(sscreen, resource, alloc_size, alignment);
+
+ if (!si_alloc_resource(sscreen, resource))
+ goto error;
+ } else {
+ resource->buf = imported_buf;
+ resource->gpu_address = sscreen->ws->buffer_get_virtual_address(resource->buf);
+ resource->bo_size = imported_buf->size;
+ resource->bo_alignment = imported_buf->alignment;
+ resource->domains = sscreen->ws->buffer_get_initial_domain(resource->buf);
+ if (resource->domains & RADEON_DOMAIN_VRAM)
+ resource->vram_usage = resource->bo_size;
+ else if (resource->domains & RADEON_DOMAIN_GTT)
+ resource->gart_usage = resource->bo_size;
+ if (sscreen->ws->buffer_get_flags)
+ resource->flags = sscreen->ws->buffer_get_flags(resource->buf);
+ }
+
+ if (tex->cmask_buffer) {
+ /* Initialize the cmask to 0xCC (= compressed state). */
+ si_screen_clear_buffer(sscreen, &tex->cmask_buffer->b.b, tex->surface.cmask_offset,
+ tex->surface.cmask_size, 0xCCCCCCCC);
+ }
+ if (tex->surface.htile_offset) {
+ uint32_t clear_value = 0;
+
+ if (sscreen->info.chip_class >= GFX9 || tex->tc_compatible_htile)
+ clear_value = 0x0000030F;
+
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.htile_offset,
+ tex->surface.htile_size, clear_value);
+ }
+
+ /* Initialize DCC only if the texture is not being imported. */
+ if (!(surface->flags & RADEON_SURF_IMPORTED) && tex->surface.dcc_offset) {
+ /* Clear DCC to black for all tiles with DCC enabled.
+ *
+ * This fixes corruption in 3DMark Slingshot Extreme, which
+ * uses uninitialized textures, causing corruption.
+ */
+ if (tex->surface.num_dcc_levels == tex->buffer.b.b.last_level + 1 &&
+ tex->buffer.b.b.nr_samples <= 2) {
+ /* Simple case - all tiles have DCC enabled. */
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.dcc_offset,
+ tex->surface.dcc_size, DCC_CLEAR_COLOR_0000);
+ } else if (sscreen->info.chip_class >= GFX9) {
+ /* Clear to uncompressed. Clearing this to black is complicated. */
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.dcc_offset,
+ tex->surface.dcc_size, DCC_UNCOMPRESSED);
+ } else {
+ /* GFX8: Initialize mipmap levels and multisamples separately. */
+ if (tex->buffer.b.b.nr_samples >= 2) {
+ /* Clearing this to black is complicated. */
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.dcc_offset,
+ tex->surface.dcc_size, DCC_UNCOMPRESSED);
+ } else {
+ /* Clear the enabled mipmap levels to black. */
+ unsigned size = 0;
+
+ for (unsigned i = 0; i < tex->surface.num_dcc_levels; i++) {
+ if (!tex->surface.u.legacy.level[i].dcc_fast_clear_size)
+ break;
+
+ size = tex->surface.u.legacy.level[i].dcc_offset +
+ tex->surface.u.legacy.level[i].dcc_fast_clear_size;
+ }
+
+ /* Mipmap levels with DCC. */
+ if (size) {
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.dcc_offset, size,
+ DCC_CLEAR_COLOR_0000);
+ }
+ /* Mipmap levels without DCC. */
+ if (size != tex->surface.dcc_size) {
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.dcc_offset + size,
+ tex->surface.dcc_size - size, DCC_UNCOMPRESSED);
+ }
+ }
+ }
+
+ /* Initialize displayable DCC that requires the retile blit. */
+ if (tex->surface.dcc_retile_map_offset) {
+ /* Uninitialized DCC can hang the display hw.
+ * Clear to white to indicate that. */
+ si_screen_clear_buffer(sscreen, &tex->buffer.b.b, tex->surface.display_dcc_offset,
+ tex->surface.u.gfx9.display_dcc_size, DCC_CLEAR_COLOR_1111);
+
+ /* Upload the DCC retile map.
+ * Use a staging buffer for the upload, because
+ * the buffer backing the texture is unmappable.
+ */
+ bool use_uint16 = tex->surface.u.gfx9.dcc_retile_use_uint16;
+ unsigned num_elements = tex->surface.u.gfx9.dcc_retile_num_elements;
+ unsigned dcc_retile_map_size = num_elements * (use_uint16 ? 2 : 4);
+ struct si_resource *buf = si_aligned_buffer_create(screen, 0, PIPE_USAGE_STREAM,
+ dcc_retile_map_size,
+ sscreen->info.tcc_cache_line_size);
+ void *map = sscreen->ws->buffer_map(buf->buf, NULL, PIPE_TRANSFER_WRITE);
+
+ /* Upload the retile map into the staging buffer. */
+ memcpy(map, tex->surface.u.gfx9.dcc_retile_map, dcc_retile_map_size);
+
+ /* Copy the staging buffer to the buffer backing the texture. */
+ struct si_context *sctx = (struct si_context *)sscreen->aux_context;
+
+ assert(tex->surface.dcc_retile_map_offset <= UINT_MAX);
+ simple_mtx_lock(&sscreen->aux_context_lock);
+ si_sdma_copy_buffer(sctx, &tex->buffer.b.b, &buf->b.b, tex->surface.dcc_retile_map_offset,
+ 0, buf->b.b.width0);
+ sscreen->aux_context->flush(sscreen->aux_context, NULL, 0);
+ simple_mtx_unlock(&sscreen->aux_context_lock);
+
+ si_resource_reference(&buf, NULL);
+ }
+ }
+
+ /* Initialize the CMASK base register value. */
+ tex->cmask_base_address_reg = (tex->buffer.gpu_address + tex->surface.cmask_offset) >> 8;
+
+ if (sscreen->debug_flags & DBG(VM)) {
+ fprintf(stderr,
+ "VM start=0x%" PRIX64 " end=0x%" PRIX64
+ " | Texture %ix%ix%i, %i levels, %i samples, %s\n",
+ tex->buffer.gpu_address, tex->buffer.gpu_address + tex->buffer.buf->size,
+ base->width0, base->height0, util_num_layers(base, 0), base->last_level + 1,
+ base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format));
+ }
+
+ if (sscreen->debug_flags & DBG(TEX)) {
+ puts("Texture:");
+ struct u_log_context log;
+ u_log_context_init(&log);
+ si_print_texture_info(sscreen, tex, &log);
+ u_log_new_page_print(&log, stdout);
+ fflush(stdout);
+ u_log_context_destroy(&log);
+ }
+
+ return tex;
+
+error:
+ FREE(tex);
+ return NULL;
+}