- struct si_texture *tex;
- struct r600_resource *resource;
- struct si_screen *sscreen = (struct si_screen*)screen;
-
- tex = CALLOC_STRUCT(si_texture);
- if (!tex)
- return NULL;
-
- resource = &tex->buffer;
- resource->b.b = *base;
- resource->b.b.next = NULL;
- 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;
- tex->size = tex->surface.surf_size;
-
- tex->tc_compatible_htile = tex->surface.htile_size != 0 &&
- (tex->surface.flags &
- RADEON_SURF_TC_COMPATIBLE_HTILE);
-
- /* TC-compatible HTILE:
- * - VI only supports Z32_FLOAT.
- * - GFX9 only supports Z32_FLOAT and Z16_UNORM. */
- if (tex->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;
-
- if (tex->is_depth) {
- if (sscreen->info.chip_class >= GFX9) {
- tex->can_sample_z = true;
- tex->can_sample_s = true;
- } else {
- tex->can_sample_z = !tex->surface.u.legacy.depth_adjusted;
- tex->can_sample_s = !tex->surface.u.legacy.stencil_adjusted;
- }
-
- if (!(base->flags & (SI_RESOURCE_FLAG_TRANSFER |
- SI_RESOURCE_FLAG_FLUSHED_DEPTH))) {
- tex->db_compatible = true;
-
- if (!(sscreen->debug_flags & DBG(NO_HYPERZ)))
- si_texture_allocate_htile(sscreen, tex);
- }
- } else {
- if (base->nr_samples > 1 &&
- !buf &&
- !(sscreen->debug_flags & DBG(NO_FMASK))) {
- /* Allocate FMASK. */
- tex->fmask_offset = align64(tex->size,
- tex->surface.fmask_alignment);
- tex->size = tex->fmask_offset + tex->surface.fmask_size;
-
- /* Allocate CMASK. */
- tex->cmask_offset = align64(tex->size, tex->surface.cmask_alignment);
- tex->size = tex->cmask_offset + tex->surface.cmask_size;
- tex->cb_color_info |= S_028C70_FAST_CLEAR(1);
- tex->cmask_buffer = &tex->buffer;
-
- if (!tex->surface.fmask_size || !tex->surface.cmask_size) {
- FREE(tex);
- return NULL;
- }
- }
-
- /* Shared textures must always set up DCC here.
- * If it's not present, it will be disabled by
- * apply_opaque_metadata later.
- */
- if (tex->surface.dcc_size &&
- (buf || !(sscreen->debug_flags & DBG(NO_DCC))) &&
- !(tex->surface.flags & RADEON_SURF_SCANOUT)) {
- /* Reserve space for the DCC buffer. */
- tex->dcc_offset = align64(tex->size, tex->surface.dcc_alignment);
- tex->size = tex->dcc_offset + tex->surface.dcc_size;
- }
- }
-
- /* Now create the backing buffer. */
- if (!buf) {
- si_init_resource_fields(sscreen, resource, tex->size,
- tex->surface.surf_alignment);
-
- if (!si_alloc_resource(sscreen, resource)) {
- FREE(tex);
- return NULL;
- }
- } else {
- resource->buf = buf;
- resource->gpu_address = sscreen->ws->buffer_get_virtual_address(resource->buf);
- resource->bo_size = buf->size;
- resource->bo_alignment = buf->alignment;
- resource->domains = sscreen->ws->buffer_get_initial_domain(resource->buf);
- if (resource->domains & RADEON_DOMAIN_VRAM)
- resource->vram_usage = buf->size;
- else if (resource->domains & RADEON_DOMAIN_GTT)
- resource->gart_usage = buf->size;
- }
-
- if (tex->cmask_buffer) {
- /* Initialize the cmask to 0xCC (= compressed state). */
- si_screen_clear_buffer(sscreen, &tex->cmask_buffer->b.b,
- tex->cmask_offset, tex->surface.cmask_size,
- 0xCCCCCCCC);
- }
- if (tex->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->htile_offset,
- tex->surface.htile_size,
- clear_value);
- }
-
- /* Initialize DCC only if the texture is not being imported. */
- if (!buf && tex->dcc_offset) {
- si_screen_clear_buffer(sscreen, &tex->buffer.b.b,
- tex->dcc_offset,
- tex->surface.dcc_size,
- 0xFFFFFFFF);
- }
-
- /* Initialize the CMASK base register value. */
- tex->cmask_base_address_reg =
- (tex->buffer.gpu_address + tex->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;
+ 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;