/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean virgl_is_format_supported( struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct virgl_screen *vscreen = virgl_screen(screen); const struct util_format_description *format_desc; int i; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY); format_desc = util_format_description(format); if (!format_desc) return FALSE; if (util_format_is_intensity(format)) return FALSE; if (sample_count > 1) { if (!vscreen->caps.caps.v1.bset.texture_multisample) return FALSE; if (sample_count > vscreen->caps.caps.v1.max_samples) return FALSE; } if (bind & PIPE_BIND_VERTEX_BUFFER) { return virgl_is_vertex_format_supported(screen, format); } if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* * Although possible, it is unnatural to render into compressed or YUV * surfaces. So disable these here to avoid going into weird paths * inside the state trackers. */ if (format_desc->block.width != 1 || format_desc->block.height != 1) return FALSE; { int big = format / 32; int small = format % 32; if (!(vscreen->caps.caps.v1.render.bitmask[big] & (1 << small))) return FALSE; } } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; } /* * All other operations (sampling, transfer, etc). */ if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { if (util_format_s3tc_enabled) goto out_lookup; return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_RGTC) { goto out_lookup; } if (format == PIPE_FORMAT_R11G11B10_FLOAT) { goto out_lookup; } else if (format == PIPE_FORMAT_R9G9B9E5_FLOAT) { goto out_lookup; } /* Find the first non-VOID channel. */ for (i = 0; i < 4; i++) { if (format_desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { break; } } if (i == 4) return FALSE; /* no L4A4 */ if (format_desc->nr_channels < 4 && format_desc->channel[i].size == 4) return FALSE; out_lookup: { int big = format / 32; int small = format % 32; if (!(vscreen->caps.caps.v1.sampler.bitmask[big] & (1 << small))) return FALSE; } /* * Everything else should be supported by u_format. */ 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; } } 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->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; }
/* Translate a pipe_format into a useful texture format for sampling. * * Some special formats are translated directly using R300_EASY_TX_FORMAT, * but the majority of them is translated in a generic way, automatically * supporting all the formats hw can support. * * R300_EASY_TX_FORMAT swizzles the texture. * Note the signature of R300_EASY_TX_FORMAT: * R300_EASY_TX_FORMAT(B, G, R, A, FORMAT); * * The FORMAT specifies how the texture sampler will treat the texture, and * makes available X, Y, Z, W, ZERO, and ONE for swizzling. */ uint32_t r300_translate_texformat(enum pipe_format format, const unsigned char *swizzle_view, boolean is_r500, boolean dxtc_swizzle) { uint32_t result = 0; const struct util_format_description *desc; unsigned i; boolean uniform = TRUE; const uint32_t sign_bit[4] = { R300_TX_FORMAT_SIGNED_W, R300_TX_FORMAT_SIGNED_Z, R300_TX_FORMAT_SIGNED_Y, R300_TX_FORMAT_SIGNED_X, }; desc = util_format_description(format); /* Colorspace (return non-RGB formats directly). */ switch (desc->colorspace) { /* Depth stencil formats. * Swizzles are added in r300_merge_textures_and_samplers. */ case UTIL_FORMAT_COLORSPACE_ZS: switch (format) { case PIPE_FORMAT_Z16_UNORM: return R300_TX_FORMAT_X16; case PIPE_FORMAT_X8Z24_UNORM: case PIPE_FORMAT_S8_UINT_Z24_UNORM: if (is_r500) return R500_TX_FORMAT_Y8X24; else return R300_TX_FORMAT_Y16X16; default: return ~0; /* Unsupported. */ } /* YUV formats. */ case UTIL_FORMAT_COLORSPACE_YUV: result |= R300_TX_FORMAT_YUV_TO_RGB; switch (format) { case PIPE_FORMAT_UYVY: return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result; case PIPE_FORMAT_YUYV: return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result; default: return ~0; /* Unsupported/unknown. */ } /* Add gamma correction. */ case UTIL_FORMAT_COLORSPACE_SRGB: result |= R300_TX_FORMAT_GAMMA; break; default: switch (format) { /* Same as YUV but without the YUR->RGB conversion. */ case PIPE_FORMAT_R8G8_B8G8_UNORM: return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result; case PIPE_FORMAT_G8R8_G8B8_UNORM: return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result; default:; } } /* Add swizzling. */ /* The RGTC1_SNORM and LATC1_SNORM swizzle is done in the shader. */ if (format != PIPE_FORMAT_RGTC1_SNORM && format != PIPE_FORMAT_LATC1_SNORM) { if (util_format_is_compressed(format) && dxtc_swizzle && format != PIPE_FORMAT_RGTC2_UNORM && format != PIPE_FORMAT_RGTC2_SNORM && format != PIPE_FORMAT_LATC2_UNORM && format != PIPE_FORMAT_LATC2_SNORM) { result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view, TRUE); } else { result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view, FALSE); } } /* S3TC formats. */ if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { if (!util_format_s3tc_enabled) { return ~0; /* Unsupported. */ } switch (format) { case PIPE_FORMAT_DXT1_RGB: case PIPE_FORMAT_DXT1_RGBA: case PIPE_FORMAT_DXT1_SRGB: case PIPE_FORMAT_DXT1_SRGBA: return R300_TX_FORMAT_DXT1 | result; case PIPE_FORMAT_DXT3_RGBA: case PIPE_FORMAT_DXT3_SRGBA: return R300_TX_FORMAT_DXT3 | result; case PIPE_FORMAT_DXT5_RGBA: case PIPE_FORMAT_DXT5_SRGBA: return R300_TX_FORMAT_DXT5 | result; default: return ~0; /* Unsupported/unknown. */ } } /* RGTC formats. */ if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) { switch (format) { case PIPE_FORMAT_RGTC1_SNORM: case PIPE_FORMAT_LATC1_SNORM: case PIPE_FORMAT_LATC1_UNORM: case PIPE_FORMAT_RGTC1_UNORM: return R500_TX_FORMAT_ATI1N | result; case PIPE_FORMAT_RGTC2_SNORM: case PIPE_FORMAT_LATC2_SNORM: result |= sign_bit[1] | sign_bit[0]; case PIPE_FORMAT_RGTC2_UNORM: case PIPE_FORMAT_LATC2_UNORM: return R400_TX_FORMAT_ATI2N | result; default: return ~0; /* Unsupported/unknown. */ } } /* This is truly a special format. * It stores R8G8 and B is computed using sqrt(1 - R^2 - G^2) * in the sampler unit. Also known as D3DFMT_CxV8U8. */ if (format == PIPE_FORMAT_R8G8Bx_SNORM) { return R300_TX_FORMAT_CxV8U8 | result; } /* Integer and fixed-point 16.16 textures are not supported. */ for (i = 0; i < 4; i++) { if (desc->channel[i].type == UTIL_FORMAT_TYPE_FIXED || ((desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED || desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) && (!desc->channel[i].normalized || desc->channel[i].pure_integer))) { return ~0; /* Unsupported/unknown. */ } } /* Add sign. */ for (i = 0; i < desc->nr_channels; i++) { if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { result |= sign_bit[i]; } } /* See whether the components are of the same size. */ for (i = 1; i < desc->nr_channels; i++) { uniform = uniform && desc->channel[0].size == desc->channel[i].size; } /* Non-uniform formats. */ if (!uniform) { switch (desc->nr_channels) { case 3: if (desc->channel[0].size == 5 && desc->channel[1].size == 6 && desc->channel[2].size == 5) { return R300_TX_FORMAT_Z5Y6X5 | result; } if (desc->channel[0].size == 5 && desc->channel[1].size == 5 && desc->channel[2].size == 6) { return R300_TX_FORMAT_Z6Y5X5 | result; } if (desc->channel[0].size == 2 && desc->channel[1].size == 3 && desc->channel[2].size == 3) { return R300_TX_FORMAT_Z3Y3X2 | result; } return ~0; /* Unsupported/unknown. */ case 4: if (desc->channel[0].size == 5 && desc->channel[1].size == 5 && desc->channel[2].size == 5 && desc->channel[3].size == 1) { return R300_TX_FORMAT_W1Z5Y5X5 | result; } if (desc->channel[0].size == 10 && desc->channel[1].size == 10 && desc->channel[2].size == 10 && desc->channel[3].size == 2) { return R300_TX_FORMAT_W2Z10Y10X10 | result; } } return ~0; /* Unsupported/unknown. */ } /* Find the first non-VOID channel. */ for (i = 0; i < 4; i++) { if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { break; } } if (i == 4) return ~0; /* Unsupported/unknown. */ /* And finally, uniform formats. */ switch (desc->channel[i].type) { case UTIL_FORMAT_TYPE_UNSIGNED: case UTIL_FORMAT_TYPE_SIGNED: if (!desc->channel[i].normalized && desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { return ~0; } switch (desc->channel[i].size) { case 4: switch (desc->nr_channels) { case 2: return R300_TX_FORMAT_Y4X4 | result; case 4: return R300_TX_FORMAT_W4Z4Y4X4 | result; } return ~0; case 8: switch (desc->nr_channels) { case 1: return R300_TX_FORMAT_X8 | result; case 2: return R300_TX_FORMAT_Y8X8 | result; case 4: return R300_TX_FORMAT_W8Z8Y8X8 | result; } return ~0; case 16: switch (desc->nr_channels) { case 1: return R300_TX_FORMAT_X16 | result; case 2: return R300_TX_FORMAT_Y16X16 | result; case 4: return R300_TX_FORMAT_W16Z16Y16X16 | result; } } return ~0; case UTIL_FORMAT_TYPE_FLOAT: switch (desc->channel[i].size) { case 16: switch (desc->nr_channels) { case 1: return R300_TX_FORMAT_16F | result; case 2: return R300_TX_FORMAT_16F_16F | result; case 4: return R300_TX_FORMAT_16F_16F_16F_16F | result; } return ~0; case 32: switch (desc->nr_channels) { case 1: return R300_TX_FORMAT_32F | result; case 2: return R300_TX_FORMAT_32F_32F | result; case 4: return R300_TX_FORMAT_32F_32F_32F_32F | result; } } } return ~0; /* Unsupported/unknown. */ }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean llvmpipe_is_format_supported( struct pipe_screen *_screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; const struct util_format_description *format_desc; format_desc = util_format_description(format); if (!format_desc) return FALSE; /* Z16 support is missing, which breaks the blit */ if (format == PIPE_FORMAT_Z16_UNORM) return FALSE; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE); if (sample_count > 1) return FALSE; if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB) return FALSE; if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) return FALSE; assert(format_desc->block.width == 1); assert(format_desc->block.height == 1); if (format_desc->is_mixed) return FALSE; if (!format_desc->is_array && !format_desc->is_bitmask) return FALSE; /* * XXX refuse formats known to crash in generate_unswizzled_blend(). * These include all 3-channel 24bit RGB8 variants, plus 48bit * (except those using floats) 3-channel RGB16 variants (the latter * seems to be more of a llvm bug though). * The mesa state tracker only seems to use these for SINT/UINT formats. */ if (format_desc->is_array && format_desc->nr_channels == 3) { if (format_desc->block.bits == 24 || (format_desc->block.bits == 48 && !util_format_is_float(format))) { return FALSE; } } } if (bind & PIPE_BIND_DISPLAY_TARGET) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) return FALSE; if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* FIXME: Temporary restriction. See lp_state_fs.c. */ if (format_desc->block.bits != 32) return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { return util_format_s3tc_enabled; } /* * Everything can be supported by u_format * (those without fetch_rgba_float might be not but shouldn't hit that) */ return TRUE; }
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; }
/* Copy a block of pixels from one surface to another. */ static void r300_resource_copy_region(struct pipe_context *pipe, struct pipe_resource *dst, unsigned dst_level, unsigned dstx, unsigned dsty, unsigned dstz, struct pipe_resource *src, unsigned src_level, const struct pipe_box *src_box) { struct pipe_screen *screen = pipe->screen; struct r300_context *r300 = r300_context(pipe); struct pipe_framebuffer_state *fb = (struct pipe_framebuffer_state*)r300->fb_state.state; unsigned src_width0 = r300_resource(src)->tex.width0; unsigned src_height0 = r300_resource(src)->tex.height0; unsigned dst_width0 = r300_resource(dst)->tex.width0; unsigned dst_height0 = r300_resource(dst)->tex.height0; unsigned layout; struct pipe_box box, dstbox; struct pipe_sampler_view src_templ, *src_view; struct pipe_surface dst_templ, *dst_view; /* Fallback for buffers. */ if ((dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) || !r300_is_blit_supported(dst->format)) { util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level, src_box); return; } /* Can't read MSAA textures. */ if (src->nr_samples > 1 || dst->nr_samples > 1) { return; } /* The code below changes the texture format so that the copy can be done * on hardware. E.g. depth-stencil surfaces are copied as RGBA * colorbuffers. */ util_blitter_default_dst_texture(&dst_templ, dst, dst_level, dstz); util_blitter_default_src_texture(&src_templ, src, src_level); layout = util_format_description(dst_templ.format)->layout; /* Handle non-renderable plain formats. */ if (layout == UTIL_FORMAT_LAYOUT_PLAIN && (!screen->is_format_supported(screen, src_templ.format, src->target, src->nr_samples, PIPE_BIND_SAMPLER_VIEW) || !screen->is_format_supported(screen, dst_templ.format, dst->target, dst->nr_samples, PIPE_BIND_RENDER_TARGET))) { switch (util_format_get_blocksize(dst_templ.format)) { case 1: dst_templ.format = PIPE_FORMAT_I8_UNORM; break; case 2: dst_templ.format = PIPE_FORMAT_B4G4R4A4_UNORM; break; case 4: dst_templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; break; case 8: dst_templ.format = PIPE_FORMAT_R16G16B16A16_UNORM; break; default: debug_printf("r300: copy_region: Unhandled format: %s. Falling back to software.\n" "r300: copy_region: Software fallback doesn't work for tiled textures.\n", util_format_short_name(dst_templ.format)); } src_templ.format = dst_templ.format; } /* Handle compressed formats. */ if (layout == UTIL_FORMAT_LAYOUT_S3TC || layout == UTIL_FORMAT_LAYOUT_RGTC) { assert(src_templ.format == dst_templ.format); box = *src_box; src_box = &box; dst_width0 = align(dst_width0, 4); dst_height0 = align(dst_height0, 4); src_width0 = align(src_width0, 4); src_height0 = align(src_height0, 4); box.width = align(box.width, 4); box.height = align(box.height, 4); switch (util_format_get_blocksize(dst_templ.format)) { case 8: /* one 4x4 pixel block has 8 bytes. * we set 1 pixel = 4 bytes ===> 1 block corrensponds to 2 pixels. */ dst_templ.format = PIPE_FORMAT_R8G8B8A8_UNORM; dst_width0 = dst_width0 / 2; src_width0 = src_width0 / 2; dstx /= 2; box.x /= 2; box.width /= 2; break; case 16: /* one 4x4 pixel block has 16 bytes. * we set 1 pixel = 4 bytes ===> 1 block corresponds to 4 pixels. */ dst_templ.format = PIPE_FORMAT_R8G8B8A8_UNORM; break; } src_templ.format = dst_templ.format; dst_height0 = dst_height0 / 4; src_height0 = src_height0 / 4; dsty /= 4; box.y /= 4; box.height /= 4; } /* Fallback for textures. */ if (!screen->is_format_supported(screen, dst_templ.format, dst->target, dst->nr_samples, PIPE_BIND_RENDER_TARGET) || !screen->is_format_supported(screen, src_templ.format, src->target, src->nr_samples, PIPE_BIND_SAMPLER_VIEW)) { assert(0 && "this shouldn't happen, update r300_is_blit_supported"); util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level, src_box); return; } /* Decompress ZMASK. */ if (r300->zmask_in_use && !r300->locked_zbuffer) { if (fb->zsbuf->texture == src || fb->zsbuf->texture == dst) { r300_decompress_zmask(r300); } } dst_view = r300_create_surface_custom(pipe, dst, &dst_templ, dst_width0, dst_height0); src_view = r300_create_sampler_view_custom(pipe, src, &src_templ, src_width0, src_height0); u_box_3d(dstx, dsty, dstz, abs(src_box->width), abs(src_box->height), abs(src_box->depth), &dstbox); r300_blitter_begin(r300, R300_COPY); util_blitter_blit_generic(r300->blitter, dst_view, &dstbox, src_view, src_box, src_width0, src_height0, PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL); r300_blitter_end(r300); pipe_surface_reference(&dst_view, NULL); pipe_sampler_view_reference(&src_view, 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; }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean llvmpipe_is_format_supported( struct pipe_screen *_screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; const struct util_format_description *format_desc; format_desc = util_format_description(format); if (!format_desc) return FALSE; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY); if (sample_count > 1) return FALSE; if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) { /* this is a lie actually other formats COULD exist where we would fail */ if (format_desc->nr_channels < 3) return FALSE; } else if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB) return FALSE; if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN && format != PIPE_FORMAT_R11G11B10_FLOAT) return FALSE; assert(format_desc->block.width == 1); assert(format_desc->block.height == 1); if (format_desc->is_mixed) return FALSE; if (!format_desc->is_array && !format_desc->is_bitmask && format != PIPE_FORMAT_R11G11B10_FLOAT) return FALSE; /* * XXX refuse formats known to crash in generate_unswizzled_blend(). * These include all 3-channel 24bit RGB8 variants, plus 48bit * (except those using floats) 3-channel RGB16 variants (the latter * seems to be more of a llvm bug though). * The mesa state tracker only seems to use these for SINT/UINT formats. */ if (format_desc->is_array && format_desc->nr_channels == 3) { if (format_desc->block.bits == 24 || (format_desc->block.bits == 48 && !util_format_is_float(format))) { return FALSE; } } } if (bind & PIPE_BIND_DISPLAY_TARGET) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) return FALSE; if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* TODO: Support stencil-only formats */ if (format_desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) { return FALSE; } } if (format_desc->layout == UTIL_FORMAT_LAYOUT_BPTC) { /* Software decoding is not hooked up. */ return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_ETC && format != PIPE_FORMAT_ETC1_RGB8) return FALSE; if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { return util_format_s3tc_enabled; } /* * Everything can be supported by u_format * (those without fetch_rgba_float might be not but shouldn't hit that) */ return TRUE; }
/** * Returns the largest legal index value plus one for the current set * of bound vertex buffers. Regardless of any other consideration, * all vertex lookups need to be clamped to 0..max_index-1 to prevent * an out-of-bound access. * * Note that if zero is returned it means that one or more buffers is * too small to contain any valid vertex data. */ unsigned util_draw_max_index( const struct pipe_vertex_buffer *vertex_buffers, const struct pipe_vertex_element *vertex_elements, unsigned nr_vertex_elements, const struct pipe_draw_info *info) { unsigned max_index; unsigned i; max_index = ~0U - 1; for (i = 0; i < nr_vertex_elements; i++) { const struct pipe_vertex_element *element = &vertex_elements[i]; const struct pipe_vertex_buffer *buffer = &vertex_buffers[element->vertex_buffer_index]; unsigned buffer_size; const struct util_format_description *format_desc; unsigned format_size; if (!buffer->buffer) { continue; } assert(buffer->buffer->height0 == 1); assert(buffer->buffer->depth0 == 1); buffer_size = buffer->buffer->width0; format_desc = util_format_description(element->src_format); assert(format_desc->block.width == 1); assert(format_desc->block.height == 1); assert(format_desc->block.bits % 8 == 0); format_size = format_desc->block.bits/8; if (buffer->buffer_offset >= buffer_size) { /* buffer is too small */ return 0; } buffer_size -= buffer->buffer_offset; if (element->src_offset >= buffer_size) { /* buffer is too small */ return 0; } buffer_size -= element->src_offset; if (format_size > buffer_size) { /* buffer is too small */ return 0; } buffer_size -= format_size; if (buffer->stride != 0) { unsigned buffer_max_index; buffer_max_index = buffer_size / buffer->stride; if (element->instance_divisor == 0) { /* Per-vertex data */ max_index = MIN2(max_index, buffer_max_index); } else { /* Per-instance data. Simply make sure the state tracker didn't * request more instances than those that fit in the buffer */ if ((info->start_instance + info->instance_count)/element->instance_divisor > (buffer_max_index + 1)) { /* FIXME: We really should stop thinking in terms of maximum * indices/instances and simply start clamping against buffer * size. */ debug_printf("%s: too many instances for vertex buffer\n", __FUNCTION__); return 0; } } } } return max_index + 1; }
/** * 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 < Elements(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; }
int main(int argc, char** argv) { struct translate *(*create_fn)(const struct translate_key *key) = 0; struct translate_key key; unsigned output_format; unsigned input_format; unsigned buffer_size = 4096; unsigned char* buffer[5]; unsigned char* byte_buffer; float* float_buffer; double* double_buffer; uint16_t *half_buffer; unsigned * elts; unsigned count = 4; unsigned i, j, k; unsigned passed = 0; unsigned total = 0; const float error = 0.03125; create_fn = 0; util_cpu_detect(); if (argc <= 1 || !strcmp(argv[1], "default") ) create_fn = translate_create; else if (!strcmp(argv[1], "generic")) create_fn = translate_generic_create; else if (!strcmp(argv[1], "x86")) create_fn = translate_sse2_create; else if (!strcmp(argv[1], "nosse")) { util_cpu_caps.has_sse = 0; util_cpu_caps.has_sse2 = 0; util_cpu_caps.has_sse3 = 0; util_cpu_caps.has_sse4_1 = 0; create_fn = translate_sse2_create; } else if (!strcmp(argv[1], "sse")) { if(!util_cpu_caps.has_sse || !rtasm_cpu_has_sse()) { printf("Error: CPU doesn't support SSE (test with qemu)\n"); return 2; } util_cpu_caps.has_sse2 = 0; util_cpu_caps.has_sse3 = 0; util_cpu_caps.has_sse4_1 = 0; create_fn = translate_sse2_create; } else if (!strcmp(argv[1], "sse2")) { if(!util_cpu_caps.has_sse2 || !rtasm_cpu_has_sse()) { printf("Error: CPU doesn't support SSE2 (test with qemu)\n"); return 2; } util_cpu_caps.has_sse3 = 0; util_cpu_caps.has_sse4_1 = 0; create_fn = translate_sse2_create; } else if (!strcmp(argv[1], "sse3")) { if(!util_cpu_caps.has_sse3 || !rtasm_cpu_has_sse()) { printf("Error: CPU doesn't support SSE3 (test with qemu)\n"); return 2; } util_cpu_caps.has_sse4_1 = 0; create_fn = translate_sse2_create; } else if (!strcmp(argv[1], "sse4.1")) { if(!util_cpu_caps.has_sse4_1 || !rtasm_cpu_has_sse()) { printf("Error: CPU doesn't support SSE4.1 (test with qemu)\n"); return 2; } create_fn = translate_sse2_create; } if (!create_fn) { printf("Usage: ./translate_test [default|generic|x86|nosse|sse|sse2|sse3|sse4.1]\n"); return 2; } for (i = 1; i < ARRAY_SIZE(buffer); ++i) buffer[i] = align_malloc(buffer_size, 4096); byte_buffer = align_malloc(buffer_size, 4096); float_buffer = align_malloc(buffer_size, 4096); double_buffer = align_malloc(buffer_size, 4096); half_buffer = align_malloc(buffer_size, 4096); elts = align_malloc(count * sizeof *elts, 4096); key.nr_elements = 1; key.element[0].input_buffer = 0; key.element[0].input_offset = 0; key.element[0].output_offset = 0; key.element[0].type = TRANSLATE_ELEMENT_NORMAL; key.element[0].instance_divisor = 0; srand(4359025); /* avoid negative values that work badly when converted to unsigned format*/ for (i = 0; i < buffer_size; ++i) byte_buffer[i] = rand() & 0x7f7f7f7f; for (i = 0; i < buffer_size / sizeof(float); ++i) float_buffer[i] = (float)rand_double(); for (i = 0; i < buffer_size / sizeof(double); ++i) double_buffer[i] = rand_double(); for (i = 0; i < buffer_size / sizeof(double); ++i) half_buffer[i] = util_float_to_half((float) rand_double()); for (i = 0; i < count; ++i) elts[i] = i; for (output_format = 1; output_format < PIPE_FORMAT_COUNT; ++output_format) { const struct util_format_description* output_format_desc = util_format_description(output_format); unsigned output_format_size; unsigned output_normalized = 0; if (!output_format_desc || !output_format_desc->fetch_rgba_float || !output_format_desc->pack_rgba_float || output_format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB || output_format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || !translate_is_output_format_supported(output_format)) continue; for(i = 0; i < output_format_desc->nr_channels; ++i) { if(output_format_desc->channel[i].type != UTIL_FORMAT_TYPE_FLOAT) output_normalized |= (1 << output_format_desc->channel[i].normalized); } output_format_size = util_format_get_stride(output_format, 1); for (input_format = 1; input_format < PIPE_FORMAT_COUNT; ++input_format) { const struct util_format_description* input_format_desc = util_format_description(input_format); unsigned input_format_size; struct translate* translate[2]; unsigned fail = 0; unsigned used_generic = 0; unsigned input_normalized = 0; boolean input_is_float = FALSE; if (!input_format_desc || !input_format_desc->fetch_rgba_float || !input_format_desc->pack_rgba_float || input_format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB || input_format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || !translate_is_output_format_supported(input_format)) continue; input_format_size = util_format_get_stride(input_format, 1); for(i = 0; i < input_format_desc->nr_channels; ++i) { if(input_format_desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT) { input_is_float = 1; input_normalized |= 1 << 1; } else input_normalized |= (1 << input_format_desc->channel[i].normalized); } if(((input_normalized | output_normalized) == 3) || ((input_normalized & 1) && (output_normalized & 1) && input_format_size * output_format_desc->nr_channels > output_format_size * input_format_desc->nr_channels)) continue; key.element[0].input_format = input_format; key.element[0].output_format = output_format; key.output_stride = output_format_size; translate[0] = create_fn(&key); if (!translate[0]) continue; key.element[0].input_format = output_format; key.element[0].output_format = input_format; key.output_stride = input_format_size; translate[1] = create_fn(&key); if(!translate[1]) { used_generic = 1; translate[1] = translate_generic_create(&key); if(!translate[1]) continue; } for(i = 1; i < 5; ++i) memset(buffer[i], 0xcd - (0x22 * i), 4096); if(input_is_float && input_format_desc->channel[0].size == 32) buffer[0] = (unsigned char*)float_buffer; else if(input_is_float && input_format_desc->channel[0].size == 64) buffer[0] = (unsigned char*)double_buffer; else if(input_is_float && input_format_desc->channel[0].size == 16) buffer[0] = (unsigned char*)half_buffer; else if(input_is_float) abort(); else buffer[0] = byte_buffer; translate[0]->set_buffer(translate[0], 0, buffer[0], input_format_size, count - 1); translate[0]->run_elts(translate[0], elts, count, 0, 0, buffer[1]); translate[1]->set_buffer(translate[1], 0, buffer[1], output_format_size, count - 1); translate[1]->run_elts(translate[1], elts, count, 0, 0, buffer[2]); translate[0]->set_buffer(translate[0], 0, buffer[2], input_format_size, count - 1); translate[0]->run_elts(translate[0], elts, count, 0, 0, buffer[3]); translate[1]->set_buffer(translate[1], 0, buffer[3], output_format_size, count - 1); translate[1]->run_elts(translate[1], elts, count, 0, 0, buffer[4]); for (i = 0; i < count; ++i) { float a[4]; float b[4]; input_format_desc->fetch_rgba_float(a, buffer[2] + i * input_format_size, 0, 0); input_format_desc->fetch_rgba_float(b, buffer[4] + i * input_format_size, 0, 0); for (j = 0; j < count; ++j) { float d = a[j] - b[j]; if (d > error || d < -error) { fail = 1; break; } } } printf("%s%s: %s -> %s -> %s -> %s -> %s\n", fail ? "FAIL" : "PASS", used_generic ? "[GENERIC]" : "", input_format_desc->name, output_format_desc->name, input_format_desc->name, output_format_desc->name, input_format_desc->name); if (1) { for (i = 0; i < ARRAY_SIZE(buffer); ++i) { unsigned format_size = (i & 1) ? output_format_size : input_format_size; printf("%c ", (i == 2 || i == 4) ? '*' : ' '); for (j = 0; j < count; ++j) { for (k = 0; k < format_size; ++k) { printf("%02x", buffer[i][j * format_size + k]); } printf(" "); } printf("\n"); } } if (!fail) ++passed; ++total; if(translate[1]) translate[1]->release(translate[1]); translate[0]->release(translate[0]); } } printf("%u/%u tests passed for translate_%s\n", passed, total, argv[1]); return passed != total; }
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 = 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++) { 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); } } }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean llvmpipe_is_format_supported( struct pipe_screen *_screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind, unsigned geom_flags ) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; const struct util_format_description *format_desc; format_desc = util_format_description(format); if (!format_desc) return FALSE; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE); if (sample_count > 1) return FALSE; if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) return FALSE; if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) return FALSE; if (format_desc->block.width != 1 || format_desc->block.height != 1) return FALSE; } if (bind & PIPE_BIND_DISPLAY_TARGET) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) return FALSE; if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* FIXME: Temporary restriction. See lp_state_fs.c. */ if (format_desc->block.bits != 32) return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { return util_format_s3tc_enabled; } /* * Everything else should be supported by u_format. */ return TRUE; }
/* In the case of transfer_map of a multi-sample resource, call back into * pctx->transfer_map() to map the staging resource, to handle cases of * MSAA + separate_z32s8 or fake_rgtc */ static void * transfer_map_msaa(struct pipe_context *pctx, struct pipe_resource *prsc, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **pptrans) { struct pipe_screen *pscreen = pctx->screen; struct u_transfer *trans = calloc(1, sizeof(*trans)); if (!trans) return NULL; struct pipe_transfer *ptrans = &trans->base; pipe_resource_reference(&ptrans->resource, prsc); ptrans->level = level; ptrans->usage = usage; ptrans->box = *box; struct pipe_resource tmpl = { .target = prsc->target, .format = prsc->format, .width0 = box->width, .height0 = box->height, .depth0 = 1, .array_size = 1, }; trans->ss = pscreen->resource_create(pscreen, &tmpl); if (!trans->ss) { free(trans); return NULL; } if (needs_pack(usage)) { struct pipe_blit_info blit; memset(&blit, 0, sizeof(blit)); blit.src.resource = ptrans->resource; blit.src.format = ptrans->resource->format; blit.src.level = ptrans->level; blit.src.box = *box; blit.dst.resource = trans->ss; blit.dst.format = trans->ss->format; blit.dst.box.width = box->width; blit.dst.box.height = box->height; blit.dst.box.depth = 1; blit.mask = util_format_get_mask(prsc->format); blit.filter = PIPE_TEX_FILTER_NEAREST; pctx->blit(pctx, &blit); } struct pipe_box map_box = *box; map_box.x = 0; map_box.y = 0; void *ss_map = pctx->transfer_map(pctx, trans->ss, 0, usage, &map_box, &trans->trans); if (!ss_map) { free(trans); return NULL; } ptrans->stride = trans->trans->stride; *pptrans = ptrans; return ss_map; } void * u_transfer_helper_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **pptrans) { struct u_transfer_helper *helper = pctx->screen->transfer_helper; struct u_transfer *trans; struct pipe_transfer *ptrans; enum pipe_format format = prsc->format; unsigned width = box->width; unsigned height = box->height; if (!handle_transfer(prsc)) return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans); if (helper->msaa_map && (prsc->nr_samples > 1)) return transfer_map_msaa(pctx, prsc, level, usage, box, pptrans); debug_assert(box->depth == 1); trans = calloc(1, sizeof(*trans)); if (!trans) return NULL; ptrans = &trans->base; pipe_resource_reference(&ptrans->resource, prsc); ptrans->level = level; ptrans->usage = usage; ptrans->box = *box; ptrans->stride = util_format_get_stride(format, box->width); ptrans->layer_stride = ptrans->stride * box->height; trans->staging = malloc(ptrans->layer_stride); if (!trans->staging) goto fail; trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage, box, &trans->trans); if (!trans->ptr) goto fail; if (prsc->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { struct pipe_resource *stencil = helper->vtbl->get_stencil(prsc); trans->ptr2 = helper->vtbl->transfer_map(pctx, stencil, level, usage, box, &trans->trans2); if (needs_pack(usage)) { util_format_z32_float_s8x24_uint_pack_z_float(trans->staging, ptrans->stride, trans->ptr, trans->trans->stride, width, height); util_format_z32_float_s8x24_uint_pack_s_8uint(trans->staging, ptrans->stride, trans->ptr2, trans->trans2->stride, width, height); } } else if (needs_pack(usage) && util_format_description(prsc->format)->layout == UTIL_FORMAT_LAYOUT_RGTC) { switch (prsc->format) { case PIPE_FORMAT_RGTC1_UNORM: case PIPE_FORMAT_RGTC1_SNORM: case PIPE_FORMAT_LATC1_UNORM: case PIPE_FORMAT_LATC1_SNORM: util_format_rgtc1_unorm_pack_rgba_8unorm(trans->staging, ptrans->stride, trans->ptr, trans->trans->stride, width, height); break; case PIPE_FORMAT_RGTC2_UNORM: case PIPE_FORMAT_RGTC2_SNORM: case PIPE_FORMAT_LATC2_UNORM: case PIPE_FORMAT_LATC2_SNORM: util_format_rgtc2_unorm_pack_rgba_8unorm(trans->staging, ptrans->stride, trans->ptr, trans->trans->stride, width, height); break; default: assert(!"Unexpected format"); break; } } else { unreachable("bleh"); } *pptrans = ptrans; return trans->staging; fail: if (trans->trans) helper->vtbl->transfer_unmap(pctx, trans->trans); if (trans->trans2) helper->vtbl->transfer_unmap(pctx, trans->trans2); pipe_resource_reference(&ptrans->resource, NULL); free(trans->staging); free(trans); return NULL; } static void flush_region(struct pipe_context *pctx, struct pipe_transfer *ptrans, const struct pipe_box *box) { struct u_transfer_helper *helper = pctx->screen->transfer_helper; struct u_transfer *trans = u_transfer(ptrans); enum pipe_format iformat, format = ptrans->resource->format; unsigned width = box->width; unsigned height = box->height; void *src, *dst; if (!(ptrans->usage & PIPE_TRANSFER_WRITE)) return; if (trans->ss) { struct pipe_blit_info blit; memset(&blit, 0, sizeof(blit)); blit.src.resource = trans->ss; blit.src.format = trans->ss->format; blit.src.box = *box; blit.dst.resource = ptrans->resource; blit.dst.format = ptrans->resource->format; blit.dst.level = ptrans->level; u_box_2d(ptrans->box.x + box->x, ptrans->box.y + box->y, box->width, box->height, &blit.dst.box); blit.mask = util_format_get_mask(ptrans->resource->format); blit.filter = PIPE_TEX_FILTER_NEAREST; pctx->blit(pctx, &blit); return; } iformat = helper->vtbl->get_internal_format(ptrans->resource); src = (uint8_t *)trans->staging + (box->y * ptrans->stride) + (box->x * util_format_get_blocksize(format)); dst = (uint8_t *)trans->ptr + (box->y * trans->trans->stride) + (box->x * util_format_get_blocksize(iformat)); switch (format) { case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: util_format_z32_float_s8x24_uint_unpack_z_float(dst, trans->trans->stride, src, ptrans->stride, width, height); /* fallthru */ case PIPE_FORMAT_X32_S8X24_UINT: dst = (uint8_t *)trans->ptr2 + (box->y * trans->trans2->stride) + (box->x * util_format_get_blocksize(PIPE_FORMAT_S8_UINT)); util_format_z32_float_s8x24_uint_unpack_s_8uint(dst, trans->trans2->stride, src, ptrans->stride, width, height); break; case PIPE_FORMAT_RGTC1_UNORM: case PIPE_FORMAT_RGTC1_SNORM: case PIPE_FORMAT_LATC1_UNORM: case PIPE_FORMAT_LATC1_SNORM: util_format_rgtc1_unorm_unpack_rgba_8unorm(dst, trans->trans->stride, src, ptrans->stride, width, height); break; case PIPE_FORMAT_RGTC2_UNORM: case PIPE_FORMAT_RGTC2_SNORM: case PIPE_FORMAT_LATC2_UNORM: case PIPE_FORMAT_LATC2_SNORM: util_format_rgtc2_unorm_unpack_rgba_8unorm(dst, trans->trans->stride, src, ptrans->stride, width, height); break; default: assert(!"Unexpected staging transfer type"); break; } } void u_transfer_helper_transfer_flush_region(struct pipe_context *pctx, struct pipe_transfer *ptrans, const struct pipe_box *box) { struct u_transfer_helper *helper = pctx->screen->transfer_helper; if (handle_transfer(ptrans->resource)) { struct u_transfer *trans = u_transfer(ptrans); flush_region(pctx, ptrans, box); /* handle MSAA case, since there could be multiple levels of * wrapped transfer, call pctx->transfer_flush_region() * instead of helper->vtbl->transfer_flush_region() */ if (trans->ss) { pctx->transfer_flush_region(pctx, trans->trans, box); return; } helper->vtbl->transfer_flush_region(pctx, trans->trans, box); if (trans->trans2) helper->vtbl->transfer_flush_region(pctx, trans->trans2, box); } else { helper->vtbl->transfer_flush_region(pctx, ptrans, box); } } void u_transfer_helper_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans) { struct u_transfer_helper *helper = pctx->screen->transfer_helper; if (handle_transfer(ptrans->resource)) { struct u_transfer *trans = u_transfer(ptrans); if (!(ptrans->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) { struct pipe_box box; u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box); flush_region(pctx, ptrans, &box); } /* in MSAA case, there could be multiple levels of wrapping * so don't call helper->vtbl->transfer_unmap() directly */ if (trans->ss) { pctx->transfer_unmap(pctx, trans->trans); pipe_resource_reference(&trans->ss, NULL); } else { helper->vtbl->transfer_unmap(pctx, trans->trans); if (trans->trans2) helper->vtbl->transfer_unmap(pctx, trans->trans2); } free(trans); } else { helper->vtbl->transfer_unmap(pctx, ptrans); } } struct u_transfer_helper * u_transfer_helper_create(const struct u_transfer_vtbl *vtbl, bool separate_z32s8, bool fake_rgtc, bool msaa_map) { struct u_transfer_helper *helper = calloc(1, sizeof(*helper)); helper->vtbl = vtbl; helper->separate_z32s8 = separate_z32s8; helper->fake_rgtc = fake_rgtc; helper->msaa_map = msaa_map; return helper; } void u_transfer_helper_destroy(struct u_transfer_helper *helper) { free(helper); }
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; r600_mark_atom_dirty(rctx, &rctx->db_misc_state.atom); 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; r600_mark_atom_dirty(rctx, &rctx->db_misc_state.atom); } 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; r600_mark_atom_dirty(rctx, &rctx->db_misc_state.atom); }
static void * fd_resource_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **pptrans) { struct fd_context *ctx = fd_context(pctx); struct fd_resource *rsc = fd_resource(prsc); struct fd_resource_slice *slice = fd_resource_slice(rsc, level); struct fd_transfer *trans; struct pipe_transfer *ptrans; enum pipe_format format = prsc->format; uint32_t op = 0; uint32_t offset; char *buf; int ret = 0; DBG("prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", prsc, level, usage, box->width, box->height, box->x, box->y); ptrans = util_slab_alloc(&ctx->transfer_pool); if (!ptrans) return NULL; /* util_slab_alloc() doesn't zero: */ trans = fd_transfer(ptrans); memset(trans, 0, sizeof(*trans)); pipe_resource_reference(&ptrans->resource, prsc); ptrans->level = level; ptrans->usage = usage; ptrans->box = *box; ptrans->stride = util_format_get_nblocksx(format, slice->pitch) * rsc->cpp; ptrans->layer_stride = rsc->layer_first ? rsc->layer_size : slice->size0; if (usage & PIPE_TRANSFER_READ) op |= DRM_FREEDRENO_PREP_READ; if (usage & PIPE_TRANSFER_WRITE) op |= DRM_FREEDRENO_PREP_WRITE; if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { realloc_bo(rsc, fd_bo_size(rsc->bo)); if (rsc->stencil) realloc_bo(rsc->stencil, fd_bo_size(rsc->stencil->bo)); fd_invalidate_resource(ctx, prsc); } else if ((usage & PIPE_TRANSFER_WRITE) && prsc->target == PIPE_BUFFER && !util_ranges_intersect(&rsc->valid_buffer_range, box->x, box->x + box->width)) { /* We are trying to write to a previously uninitialized range. No need * to wait. */ } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { /* If the GPU is writing to the resource, or if it is reading from the * resource and we're trying to write to it, flush the renders. */ if (((ptrans->usage & PIPE_TRANSFER_WRITE) && pending(rsc, FD_PENDING_READ | FD_PENDING_WRITE)) || pending(rsc, FD_PENDING_WRITE)) fd_context_render(pctx); /* The GPU keeps track of how the various bo's are being used, and * will wait if necessary for the proper operation to have * completed. */ ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op); if (ret) goto fail; } buf = fd_bo_map(rsc->bo); if (!buf) goto fail; offset = slice->offset + box->y / util_format_get_blockheight(format) * ptrans->stride + box->x / util_format_get_blockwidth(format) * rsc->cpp + fd_resource_layer_offset(rsc, slice, box->z); if (prsc->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT || prsc->format == PIPE_FORMAT_X32_S8X24_UINT) { assert(trans->base.box.depth == 1); trans->base.stride = trans->base.box.width * rsc->cpp * 2; trans->staging = malloc(trans->base.stride * trans->base.box.height); if (!trans->staging) goto fail; /* if we're not discarding the whole range (or resource), we must copy * the real data in. */ if (!(usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE | PIPE_TRANSFER_DISCARD_RANGE))) { struct fd_resource_slice *sslice = fd_resource_slice(rsc->stencil, level); void *sbuf = fd_bo_map(rsc->stencil->bo); if (!sbuf) goto fail; float *depth = (float *)(buf + slice->offset + fd_resource_layer_offset(rsc, slice, box->z) + box->y * slice->pitch * 4 + box->x * 4); uint8_t *stencil = sbuf + sslice->offset + fd_resource_layer_offset(rsc->stencil, sslice, box->z) + box->y * sslice->pitch + box->x; if (format != PIPE_FORMAT_X32_S8X24_UINT) util_format_z32_float_s8x24_uint_pack_z_float( trans->staging, trans->base.stride, depth, slice->pitch * 4, box->width, box->height); util_format_z32_float_s8x24_uint_pack_s_8uint( trans->staging, trans->base.stride, stencil, sslice->pitch, box->width, box->height); } buf = trans->staging; offset = 0; } else if (rsc->internal_format != format && util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC) { assert(trans->base.box.depth == 1); trans->base.stride = util_format_get_stride( format, trans->base.box.width); trans->staging = malloc( util_format_get_2d_size(format, trans->base.stride, trans->base.box.height)); if (!trans->staging) goto fail; /* if we're not discarding the whole range (or resource), we must copy * the real data in. */ if (!(usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE | PIPE_TRANSFER_DISCARD_RANGE))) { uint8_t *rgba8 = (uint8_t *)buf + slice->offset + fd_resource_layer_offset(rsc, slice, box->z) + box->y * slice->pitch * rsc->cpp + box->x * rsc->cpp; switch (format) { case PIPE_FORMAT_RGTC1_UNORM: case PIPE_FORMAT_RGTC1_SNORM: case PIPE_FORMAT_LATC1_UNORM: case PIPE_FORMAT_LATC1_SNORM: util_format_rgtc1_unorm_pack_rgba_8unorm( trans->staging, trans->base.stride, rgba8, slice->pitch * rsc->cpp, box->width, box->height); break; case PIPE_FORMAT_RGTC2_UNORM: case PIPE_FORMAT_RGTC2_SNORM: case PIPE_FORMAT_LATC2_UNORM: case PIPE_FORMAT_LATC2_SNORM: util_format_rgtc2_unorm_pack_rgba_8unorm( trans->staging, trans->base.stride, rgba8, slice->pitch * rsc->cpp, box->width, box->height); break; default: assert(!"Unexpected format"); break; } } buf = trans->staging; offset = 0; } *pptrans = ptrans; return buf + offset; fail: fd_resource_transfer_unmap(pctx, ptrans); return NULL; }
static bool do_hardware_msaa_resolve(struct pipe_context *ctx, const struct pipe_blit_info *info) { struct r600_context *rctx = (struct r600_context*)ctx; struct r600_texture *dst = (struct r600_texture*)info->dst.resource; unsigned dst_width = u_minify(info->dst.resource->width0, info->dst.level); unsigned dst_height = u_minify(info->dst.resource->height0, info->dst.level); enum pipe_format format = info->src.format; unsigned sample_mask = rctx->b.chip_class == CAYMAN ? ~0 : ((1ull << MAX2(1, info->src.resource->nr_samples)) - 1); struct pipe_resource *tmp, templ; struct pipe_blit_info blit; /* Check basic requirements for hw resolve. */ if (!(info->src.resource->nr_samples > 1 && info->dst.resource->nr_samples <= 1 && !util_format_is_pure_integer(format) && !util_format_is_depth_or_stencil(format) && util_max_layer(info->src.resource, 0) == 0)) return false; /* Check the remaining requirements for hw resolve. */ if (util_max_layer(info->dst.resource, info->dst.level) == 0 && util_is_format_compatible(util_format_description(info->src.format), util_format_description(info->dst.format)) && !info->scissor_enable && (info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA && dst_width == info->src.resource->width0 && dst_height == info->src.resource->height0 && info->dst.box.x == 0 && info->dst.box.y == 0 && info->dst.box.width == dst_width && info->dst.box.height == dst_height && info->dst.box.depth == 1 && info->src.box.x == 0 && info->src.box.y == 0 && info->src.box.width == dst_width && info->src.box.height == dst_height && info->src.box.depth == 1 && dst->surface.level[info->dst.level].mode >= RADEON_SURF_MODE_1D && (!dst->cmask.size || !dst->dirty_level_mask) /* dst cannot be fast-cleared */) { r600_blitter_begin(ctx, R600_COLOR_RESOLVE | (info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND)); util_blitter_custom_resolve_color(rctx->blitter, info->dst.resource, info->dst.level, info->dst.box.z, info->src.resource, info->src.box.z, sample_mask, rctx->custom_blend_resolve, format); r600_blitter_end(ctx); return true; } /* Shader-based resolve is VERY SLOW. Instead, resolve into * a temporary texture and blit. */ memset(&templ, 0, sizeof(templ)); templ.target = PIPE_TEXTURE_2D; templ.format = info->src.resource->format; templ.width0 = info->src.resource->width0; templ.height0 = info->src.resource->height0; templ.depth0 = 1; templ.array_size = 1; templ.usage = PIPE_USAGE_DEFAULT; templ.flags = R600_RESOURCE_FLAG_FORCE_TILING; tmp = ctx->screen->resource_create(ctx->screen, &templ); if (!tmp) return false; /* resolve */ r600_blitter_begin(ctx, R600_COLOR_RESOLVE | (info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND)); util_blitter_custom_resolve_color(rctx->blitter, tmp, 0, 0, info->src.resource, info->src.box.z, sample_mask, rctx->custom_blend_resolve, format); r600_blitter_end(ctx); /* blit */ blit = *info; blit.src.resource = tmp; blit.src.box.z = 0; r600_blitter_begin(ctx, R600_BLIT | (info->render_condition_enable ? 0 : R600_DISABLE_RENDER_COND)); util_blitter_blit(rctx->blitter, &blit); r600_blitter_end(ctx); pipe_resource_reference(&tmp, NULL); return true; }
/** * Create a new texture object, using the given template info. */ static struct pipe_resource * fd_resource_create(struct pipe_screen *pscreen, const struct pipe_resource *tmpl) { struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); struct pipe_resource *prsc = &rsc->base.b; enum pipe_format format = tmpl->format; uint32_t size, alignment; DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " "nr_samples=%u, usage=%u, bind=%x, flags=%x", tmpl->target, util_format_name(format), tmpl->width0, tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level, tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags); if (!rsc) return NULL; *prsc = *tmpl; pipe_reference_init(&prsc->reference, 1); list_inithead(&rsc->list); prsc->screen = pscreen; util_range_init(&rsc->valid_buffer_range); rsc->base.vtbl = &fd_resource_vtbl; if (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) format = PIPE_FORMAT_Z32_FLOAT; else if (fd_screen(pscreen)->gpu_id < 400 && util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC) format = PIPE_FORMAT_R8G8B8A8_UNORM; rsc->internal_format = format; rsc->cpp = util_format_get_blocksize(format); assert(rsc->cpp); alignment = slice_alignment(pscreen, tmpl); if (is_a4xx(fd_screen(pscreen))) { switch (tmpl->target) { case PIPE_TEXTURE_3D: rsc->layer_first = false; break; default: rsc->layer_first = true; alignment = 1; break; } } size = setup_slices(rsc, alignment, format); if (rsc->layer_first) { rsc->layer_size = align(size, 4096); size = rsc->layer_size * prsc->array_size; } realloc_bo(rsc, size); if (!rsc->bo) goto fail; /* There is no native Z32F_S8 sampling or rendering format, so this must * be emulated via two separate textures. The depth texture still keeps * its Z32F_S8 format though, and we also keep a reference to a separate * S8 texture. */ if (tmpl->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { struct pipe_resource stencil = *tmpl; stencil.format = PIPE_FORMAT_S8_UINT; rsc->stencil = fd_resource(fd_resource_create(pscreen, &stencil)); if (!rsc->stencil) goto fail; } return prsc; fail: fd_resource_destroy(pscreen, prsc); return NULL; }
static void * nvfx_vtxelts_state_create(struct pipe_context *pipe, unsigned num_elements, const struct pipe_vertex_element *elements) { struct nvfx_vtxelt_state *cso = CALLOC_STRUCT(nvfx_vtxelt_state); struct translate_key transkey; unsigned per_vertex_size[16]; unsigned vb_compacted_index[16]; if(num_elements > 16) { _debug_printf("Error: application attempted to use %u vertex elements, but only 16 are supported: ignoring the rest\n", num_elements); num_elements = 16; } memset(per_vertex_size, 0, sizeof(per_vertex_size)); memcpy(cso->pipe, elements, num_elements * sizeof(elements[0])); cso->num_elements = num_elements; cso->needs_translate = FALSE; transkey.nr_elements = 0; transkey.output_stride = 0; for(unsigned i = 0; i < num_elements; ++i) { const struct pipe_vertex_element* ve = &elements[i]; if(!ve->instance_divisor) per_vertex_size[ve->vertex_buffer_index] += util_format_get_stride(ve->src_format, 1); } for(unsigned i = 0; i < 16; ++i) { if(per_vertex_size[i]) { unsigned idx = cso->num_per_vertex_buffer_infos++; cso->per_vertex_buffer_info[idx].vertex_buffer_index = i; cso->per_vertex_buffer_info[idx].per_vertex_size = per_vertex_size[i]; vb_compacted_index[i] = idx; } } for(unsigned i = 0; i < num_elements; ++i) { const struct pipe_vertex_element* ve = &elements[i]; unsigned type = nvfx_vertex_formats[ve->src_format]; unsigned ncomp = util_format_get_nr_components(ve->src_format); //if(ve->frequency != PIPE_ELEMENT_FREQUENCY_PER_VERTEX) if(ve->instance_divisor) { struct nvfx_low_frequency_element* lfve; cso->vtxfmt[i] = NV30_3D_VTXFMT_TYPE_V32_FLOAT; //if(ve->frequency == PIPE_ELEMENT_FREQUENCY_CONSTANT) if(0) lfve = &cso->constant[cso->num_constant++]; else { lfve = &cso->per_instance[cso->num_per_instance++].base; ((struct nvfx_per_instance_element*)lfve)->instance_divisor = ve->instance_divisor; } lfve->idx = i; lfve->vertex_buffer_index = ve->vertex_buffer_index; lfve->src_offset = ve->src_offset; lfve->fetch_rgba_float = util_format_description(ve->src_format)->fetch_rgba_float; lfve->ncomp = ncomp; } else { unsigned idx; idx = cso->num_per_vertex++; cso->per_vertex[idx].idx = i; cso->per_vertex[idx].vertex_buffer_index = ve->vertex_buffer_index; cso->per_vertex[idx].src_offset = ve->src_offset; idx = transkey.nr_elements++; transkey.element[idx].input_format = ve->src_format; transkey.element[idx].input_buffer = vb_compacted_index[ve->vertex_buffer_index]; transkey.element[idx].input_offset = ve->src_offset; transkey.element[idx].instance_divisor = 0; transkey.element[idx].type = TRANSLATE_ELEMENT_NORMAL; if(type) { transkey.element[idx].output_format = ve->src_format; cso->vtxfmt[i] = (ncomp << NV30_3D_VTXFMT_SIZE__SHIFT) | type; } else { unsigned float32[4] = {PIPE_FORMAT_R32_FLOAT, PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT}; transkey.element[idx].output_format = float32[ncomp - 1]; cso->needs_translate = TRUE; cso->vtxfmt[i] = (ncomp << NV30_3D_VTXFMT_SIZE__SHIFT) | NV30_3D_VTXFMT_TYPE_V32_FLOAT; } transkey.element[idx].output_offset = transkey.output_stride; transkey.output_stride += (util_format_get_stride(transkey.element[idx].output_format, 1) + 3) & ~3; } } cso->translate = translate_create(&transkey); cso->vertex_length = transkey.output_stride >> 2; cso->max_vertices_per_packet = 2047 / MAX2(cso->vertex_length, 1); return (void *)cso; }
static boolean r300_is_format_supported(struct pipe_screen* screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned usage) { uint32_t retval = 0; boolean drm_2_8_0 = r300_screen(screen)->info.drm_minor >= 8; boolean is_r500 = r300_screen(screen)->caps.is_r500; boolean is_r400 = r300_screen(screen)->caps.is_r400; boolean is_color2101010 = format == PIPE_FORMAT_R10G10B10A2_UNORM || format == PIPE_FORMAT_R10G10B10X2_SNORM || format == PIPE_FORMAT_B10G10R10A2_UNORM || format == PIPE_FORMAT_R10SG10SB10SA2U_NORM; boolean is_ati1n = format == PIPE_FORMAT_RGTC1_UNORM || format == PIPE_FORMAT_RGTC1_SNORM || format == PIPE_FORMAT_LATC1_UNORM || format == PIPE_FORMAT_LATC1_SNORM; boolean is_ati2n = format == PIPE_FORMAT_RGTC2_UNORM || format == PIPE_FORMAT_RGTC2_SNORM || format == PIPE_FORMAT_LATC2_UNORM || format == PIPE_FORMAT_LATC2_SNORM; boolean is_x16f_xy16f = format == PIPE_FORMAT_R16_FLOAT || format == PIPE_FORMAT_R16G16_FLOAT || format == PIPE_FORMAT_A16_FLOAT || format == PIPE_FORMAT_L16_FLOAT || format == PIPE_FORMAT_L16A16_FLOAT || format == PIPE_FORMAT_I16_FLOAT; boolean is_half_float = format == PIPE_FORMAT_R16_FLOAT || format == PIPE_FORMAT_R16G16_FLOAT || format == PIPE_FORMAT_R16G16B16_FLOAT || format == PIPE_FORMAT_R16G16B16A16_FLOAT; const struct util_format_description *desc; if (!util_format_is_supported(format, usage)) return FALSE; /* Check multisampling support. */ switch (sample_count) { case 0: case 1: break; case 2: case 4: case 6: /* We need DRM 2.8.0. */ if (!drm_2_8_0) { return FALSE; } /* Only support R500, because I didn't test older chipsets, * but MSAA should work there too. */ if (!is_r500 && !debug_get_bool_option("RADEON_MSAA", FALSE)) { return FALSE; } /* No texturing and scanout. */ if (usage & (PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT)) { return FALSE; } desc = util_format_description(format); if (is_r500) { /* Only allow depth/stencil, RGBA8, RGBA1010102, RGBA16F. */ if (!util_format_is_depth_or_stencil(format) && !util_format_is_rgba8_variant(desc) && !util_format_is_rgba1010102_variant(desc) && format != PIPE_FORMAT_R16G16B16A16_FLOAT) { return FALSE; } } else { /* Only allow depth/stencil, RGBA8. */ if (!util_format_is_depth_or_stencil(format) && !util_format_is_rgba8_variant(desc)) { return FALSE; } } break; default: return FALSE; } /* Check sampler format support. */ if ((usage & PIPE_BIND_SAMPLER_VIEW) && /* ATI1N is r5xx-only. */ (is_r500 || !is_ati1n) && /* ATI2N is supported on r4xx-r5xx. */ (is_r400 || is_r500 || !is_ati2n) && /* R16F and RG16F texture support was added in as late as DRM 2.8.0 */ (drm_2_8_0 || !is_x16f_xy16f) && r300_is_sampler_format_supported(format)) { retval |= PIPE_BIND_SAMPLER_VIEW; } /* Check colorbuffer format support. */ if ((usage & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) && /* 2101010 cannot be rendered to on non-r5xx. */ (!is_color2101010 || (is_r500 && drm_2_8_0)) && r300_is_colorbuffer_format_supported(format)) { retval |= usage & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED); } /* Check depth-stencil format support. */ if (usage & PIPE_BIND_DEPTH_STENCIL && r300_is_zs_format_supported(format)) { retval |= PIPE_BIND_DEPTH_STENCIL; } /* Check vertex buffer format support. */ if (usage & PIPE_BIND_VERTEX_BUFFER) { if (r300_screen(screen)->caps.has_tcl) { /* Half float is supported on >= R400. */ if ((is_r400 || is_r500 || !is_half_float) && r300_translate_vertex_data_type(format) != R300_INVALID_FORMAT) { retval |= PIPE_BIND_VERTEX_BUFFER; } } else { /* SW TCL */ if (!util_format_is_pure_integer(format)) { retval |= PIPE_BIND_VERTEX_BUFFER; } } } /* Transfers are always supported. */ if (usage & PIPE_BIND_TRANSFER_READ) retval |= PIPE_BIND_TRANSFER_READ; if (usage & PIPE_BIND_TRANSFER_WRITE) retval |= PIPE_BIND_TRANSFER_WRITE; return retval == usage; }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean llvmpipe_is_format_supported( struct pipe_screen *_screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; const struct util_format_description *format_desc; format_desc = util_format_description(format); if (!format_desc) return FALSE; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY); if (sample_count > 1) return FALSE; if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) { /* this is a lie actually other formats COULD exist where we would fail */ if (format_desc->nr_channels < 3) return FALSE; } else if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB) return FALSE; if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN && format != PIPE_FORMAT_R11G11B10_FLOAT) return FALSE; assert(format_desc->block.width == 1); assert(format_desc->block.height == 1); if (format_desc->is_mixed) return FALSE; if (!format_desc->is_array && !format_desc->is_bitmask && format != PIPE_FORMAT_R11G11B10_FLOAT) return FALSE; } if ((bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW)) && ((bind & PIPE_BIND_DISPLAY_TARGET) == 0)) { /* Disable all 3-channel formats, where channel size != 32 bits. * In some cases we run into crashes (in generate_unswizzled_blend()), * for 3-channel RGB16 variants, there was an apparent LLVM bug. * In any case, disabling the shallower 3-channel formats avoids a * number of issues with GL_ARB_copy_image support. */ if (format_desc->is_array && format_desc->nr_channels == 3 && format_desc->block.bits != 96) { return FALSE; } } if (bind & PIPE_BIND_DISPLAY_TARGET) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) return FALSE; if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* TODO: Support stencil-only formats */ if (format_desc->swizzle[0] == PIPE_SWIZZLE_NONE) { return FALSE; } } if (format_desc->layout == UTIL_FORMAT_LAYOUT_BPTC || format_desc->layout == UTIL_FORMAT_LAYOUT_ASTC) { /* Software decoding is not hooked up. */ return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_ETC && format != PIPE_FORMAT_ETC1_RGB8) return FALSE; if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { return util_format_s3tc_enabled; } /* * Everything can be supported by u_format * (those without fetch_rgba_float might be not but shouldn't hit that) */ return 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; 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 = 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; si_mark_atom_dirty(sctx, &sctx->db_render_state); }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean softpipe_is_format_supported( struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; const struct util_format_description *format_desc; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY); format_desc = util_format_description(format); if (!format_desc) return FALSE; if (sample_count > 1) return FALSE; if (bind & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* * Although possible, it is unnatural to render into compressed or YUV * surfaces. So disable these here to avoid going into weird paths * inside the state trackers. */ if (format_desc->block.width != 1 || format_desc->block.height != 1) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_BPTC) { /* Software decoding is not hooked up. */ return FALSE; } /* * All other operations (sampling, transfer, etc). */ if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { return util_format_s3tc_enabled; } /* * Everything else should be supported by u_format. */ return TRUE; }
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; }
static void vi_get_fast_clear_parameters(enum pipe_format surface_format, const union pipe_color_union *color, uint32_t* reset_value, bool* clear_words_needed) { bool values[4] = {}; int i; bool main_value = false; bool extra_value = false; int extra_channel; const struct util_format_description *desc = util_format_description(surface_format); *clear_words_needed = true; *reset_value = 0x20202020U; /* If we want to clear without needing a fast clear eliminate step, we * can set each channel to 0 or 1 (or 0/max for integer formats). We * have two sets of flags, one for the last or first channel(extra) and * one for the other channels(main). */ if (surface_format == PIPE_FORMAT_R11G11B10_FLOAT || surface_format == PIPE_FORMAT_B5G6R5_UNORM || surface_format == PIPE_FORMAT_B5G6R5_SRGB) { extra_channel = -1; } else if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) { if(r600_translate_colorswap(surface_format) <= 1) extra_channel = desc->nr_channels - 1; else extra_channel = 0; } else return; for (i = 0; i < 4; ++i) { int index = desc->swizzle[i] - UTIL_FORMAT_SWIZZLE_X; if (desc->swizzle[i] < UTIL_FORMAT_SWIZZLE_X || desc->swizzle[i] > UTIL_FORMAT_SWIZZLE_W) continue; if (util_format_is_pure_sint(surface_format)) { values[i] = color->i[i] != 0; if (color->i[i] != 0 && color->i[i] != INT32_MAX) return; } else if (util_format_is_pure_uint(surface_format)) { values[i] = color->ui[i] != 0U; if (color->ui[i] != 0U && color->ui[i] != UINT32_MAX) return; } else { values[i] = color->f[i] != 0.0F; if (color->f[i] != 0.0F && color->f[i] != 1.0F) return; } if (index == extra_channel) extra_value = values[i]; else main_value = values[i]; } for (int i = 0; i < 4; ++i) if (values[i] != main_value && desc->swizzle[i] - UTIL_FORMAT_SWIZZLE_X != extra_channel && desc->swizzle[i] >= UTIL_FORMAT_SWIZZLE_X && desc->swizzle[i] <= UTIL_FORMAT_SWIZZLE_W) return; *clear_words_needed = false; if (main_value) *reset_value |= 0x80808080U; if (extra_value) *reset_value |= 0x40404040U; }
struct pipe_sampler_view * nvc0_create_texture_view(struct pipe_context *pipe, struct pipe_resource *texture, const struct pipe_sampler_view *templ, uint32_t flags, enum pipe_texture_target target) { const struct util_format_description *desc; uint64_t address; uint32_t *tic; uint32_t swz[4]; uint32_t width, height; uint32_t depth; struct nv50_tic_entry *view; struct nv50_miptree *mt; boolean tex_int; view = MALLOC_STRUCT(nv50_tic_entry); if (!view) return NULL; mt = nv50_miptree(texture); view->pipe = *templ; view->pipe.reference.count = 1; view->pipe.texture = NULL; view->pipe.context = pipe; view->id = -1; pipe_resource_reference(&view->pipe.texture, texture); tic = &view->tic[0]; desc = util_format_description(view->pipe.format); tic[0] = nvc0_format_table[view->pipe.format].tic; tex_int = util_format_is_pure_integer(view->pipe.format); swz[0] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_r, tex_int); swz[1] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_g, tex_int); swz[2] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_b, tex_int); swz[3] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_a, tex_int); tic[0] = (tic[0] & ~NV50_TIC_0_SWIZZLE__MASK) | (swz[0] << NV50_TIC_0_MAPR__SHIFT) | (swz[1] << NV50_TIC_0_MAPG__SHIFT) | (swz[2] << NV50_TIC_0_MAPB__SHIFT) | (swz[3] << NV50_TIC_0_MAPA__SHIFT); address = mt->base.address; tic[2] = 0x10001000 | NV50_TIC_2_NO_BORDER; if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) tic[2] |= NV50_TIC_2_COLORSPACE_SRGB; if (!(flags & NV50_TEXVIEW_SCALED_COORDS)) tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; /* check for linear storage type */ if (unlikely(!nouveau_bo_memtype(nv04_resource(texture)->bo))) { if (texture->target == PIPE_BUFFER) { assert(!(tic[2] & NV50_TIC_2_NORMALIZED_COORDS)); address += view->pipe.u.buf.first_element * desc->block.bits / 8; tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_BUFFER; tic[3] = 0; tic[4] = /* width */ view->pipe.u.buf.last_element - view->pipe.u.buf.first_element + 1; tic[5] = 0; } else { /* must be 2D texture without mip maps */ tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_RECT; tic[3] = mt->level[0].pitch; tic[4] = mt->base.base.width0; tic[5] = (1 << 16) | mt->base.base.height0; } tic[6] = tic[7] = 0; tic[1] = address; tic[2] |= address >> 32; return &view->pipe; } tic[2] |= ((mt->level[0].tile_mode & 0x0f0) << (22 - 4)) | ((mt->level[0].tile_mode & 0xf00) << (25 - 8)); depth = MAX2(mt->base.base.array_size, mt->base.base.depth0); if (mt->base.base.array_size > 1) { /* there doesn't seem to be a base layer field in TIC */ address += view->pipe.u.tex.first_layer * mt->layer_stride; depth = view->pipe.u.tex.last_layer - view->pipe.u.tex.first_layer + 1; } tic[1] = address; tic[2] |= address >> 32; switch (target) { case PIPE_TEXTURE_1D: tic[2] |= NV50_TIC_2_TARGET_1D; break; case PIPE_TEXTURE_2D: tic[2] |= NV50_TIC_2_TARGET_2D; break; case PIPE_TEXTURE_RECT: tic[2] |= NV50_TIC_2_TARGET_2D; break; case PIPE_TEXTURE_3D: tic[2] |= NV50_TIC_2_TARGET_3D; break; case PIPE_TEXTURE_CUBE: depth /= 6; tic[2] |= NV50_TIC_2_TARGET_CUBE; break; case PIPE_TEXTURE_1D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY; break; case PIPE_TEXTURE_2D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY; break; case PIPE_TEXTURE_CUBE_ARRAY: depth /= 6; tic[2] |= NV50_TIC_2_TARGET_CUBE_ARRAY; break; default: NOUVEAU_ERR("unexpected/invalid texture target: %d\n", mt->base.base.target); return FALSE; } tic[3] = (flags & NV50_TEXVIEW_FILTER_MSAA8) ? 0x20000000 : 0x00300000; if (flags & NV50_TEXVIEW_ACCESS_RESOLVE) { width = mt->base.base.width0 << mt->ms_x; height = mt->base.base.height0 << mt->ms_y; } else { width = mt->base.base.width0; height = mt->base.base.height0; } tic[4] = (1 << 31) | width; tic[5] = height & 0xffff; tic[5] |= depth << 16; tic[5] |= mt->base.base.last_level << 28; /* sampling points: (?) */ if (flags & NV50_TEXVIEW_ACCESS_RESOLVE) tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; else tic[6] = 0x03000000; tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level; tic[7] |= mt->ms_mode << 12; return &view->pipe; }
static unsigned r600_choose_tiling(struct r600_common_screen *rscreen, const struct pipe_resource *templ) { const struct util_format_description *desc = util_format_description(templ->format); bool force_tiling = templ->flags & R600_RESOURCE_FLAG_FORCE_TILING; /* MSAA resources must be 2D tiled. */ if (templ->nr_samples > 1) return RADEON_SURF_MODE_2D; /* Transfer resources should be linear. */ if (templ->flags & R600_RESOURCE_FLAG_TRANSFER) return RADEON_SURF_MODE_LINEAR_ALIGNED; /* r600g: force tiling on TEXTURE_2D and TEXTURE_3D compute resources. */ if (rscreen->chip_class >= R600 && rscreen->chip_class <= CAYMAN && (templ->bind & PIPE_BIND_COMPUTE_RESOURCE) && (templ->target == PIPE_TEXTURE_2D || templ->target == PIPE_TEXTURE_3D)) force_tiling = true; /* Handle common candidates for the linear mode. * Compressed textures must always be tiled. */ if (!force_tiling && !util_format_is_compressed(templ->format)) { /* Not everything can be linear, so we cannot enforce it * for all textures. */ if ((rscreen->debug_flags & DBG_NO_TILING) && (!util_format_is_depth_or_stencil(templ->format) || !(templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH))) return RADEON_SURF_MODE_LINEAR_ALIGNED; /* Tiling doesn't work with the 422 (SUBSAMPLED) formats on R600+. */ if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) return RADEON_SURF_MODE_LINEAR_ALIGNED; /* Cursors are linear on SI. * (XXX double-check, maybe also use RADEON_SURF_SCANOUT) */ if (rscreen->chip_class >= SI && (templ->bind & PIPE_BIND_CURSOR)) return RADEON_SURF_MODE_LINEAR_ALIGNED; if (templ->bind & PIPE_BIND_LINEAR) return RADEON_SURF_MODE_LINEAR_ALIGNED; /* Textures with a very small height are recommended to be linear. */ if (templ->target == PIPE_TEXTURE_1D || templ->target == PIPE_TEXTURE_1D_ARRAY || templ->height0 <= 4) return RADEON_SURF_MODE_LINEAR_ALIGNED; /* Textures likely to be mapped often. */ if (templ->usage == PIPE_USAGE_STAGING || templ->usage == PIPE_USAGE_STREAM) return RADEON_SURF_MODE_LINEAR_ALIGNED; } /* Make small textures 1D tiled. */ if (templ->width0 <= 16 || templ->height0 <= 16 || (rscreen->debug_flags & DBG_NO_2D_TILING)) return RADEON_SURF_MODE_1D; /* The allocator will switch to 1D if needed. */ return RADEON_SURF_MODE_2D; }
/** * Copy pixel block from src surface to dst surface. * Overlapping regions are acceptable. * Flipping and stretching are supported. * \param filter one of PIPE_TEX_FILTER_NEAREST/LINEAR * \param writemask bitmask of PIPE_MASK_[RGBAZS]. Controls which channels * in the dest surface are sourced from the src surface. * Disabled color 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, MAYBE_UNUSED float z, enum pipe_tex_filter filter, uint 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_FILTER_NEAREST || filter == PIPE_TEX_FILTER_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 && (writemask & PIPE_MASK_Z); blit_stencil = is_stencil && (writemask & PIPE_MASK_S); if (is_depth || is_stencil) { assert((writemask & PIPE_MASK_RGBA) == 0); assert(blit_depth || blit_stencil); } else { assert((writemask & PIPE_MASK_ZS) == 0); assert(!blit_depth); assert(!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_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_format; info.mask = writemask; info.filter = filter; info.scissor_enable = 0; pipe->blit(pipe, &info); }
/* Shader output formats. This is essentially the swizzle from the shader * to the RB3D block. * * Note that formats are stored from C3 to C0. */ static uint32_t r300_translate_out_fmt(enum pipe_format format) { uint32_t modifier = 0; unsigned i; const struct util_format_description *desc; boolean uniform_sign; desc = util_format_description(format); /* Find the first non-VOID channel. */ for (i = 0; i < 4; i++) { if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { break; } } if (i == 4) return ~0; /* Unsupported/unknown. */ /* Specifies how the shader output is written to the fog unit. */ switch (desc->channel[i].type) { case UTIL_FORMAT_TYPE_FLOAT: switch (desc->channel[i].size) { case 32: switch (desc->nr_channels) { case 1: modifier |= R300_US_OUT_FMT_C_32_FP; break; case 2: modifier |= R300_US_OUT_FMT_C2_32_FP; break; case 4: modifier |= R300_US_OUT_FMT_C4_32_FP; break; } break; case 16: switch (desc->nr_channels) { case 1: modifier |= R300_US_OUT_FMT_C_16_FP; break; case 2: modifier |= R300_US_OUT_FMT_C2_16_FP; break; case 4: modifier |= R300_US_OUT_FMT_C4_16_FP; break; } break; } break; default: switch (desc->channel[i].size) { case 16: switch (desc->nr_channels) { case 1: modifier |= R300_US_OUT_FMT_C_16; break; case 2: modifier |= R300_US_OUT_FMT_C2_16; break; case 4: modifier |= R300_US_OUT_FMT_C4_16; break; } break; case 10: modifier |= R300_US_OUT_FMT_C4_10; break; default: /* C4_8 seems to be used for the formats whose pixel size * is <= 32 bits. */ modifier |= R300_US_OUT_FMT_C4_8; break; } } /* Add sign. */ uniform_sign = TRUE; for (i = 0; i < desc->nr_channels; i++) if (desc->channel[i].type != UTIL_FORMAT_TYPE_SIGNED) uniform_sign = FALSE; if (uniform_sign) modifier |= R300_OUT_SIGN(0xf); /* Add swizzles and return. */ switch (format) { /*** Special cases (non-standard channel mapping) ***/ /* X8 * COLORFORMAT_I8 stores the Z component (C2). */ case PIPE_FORMAT_A8_UNORM: case PIPE_FORMAT_A8_SNORM: return modifier | R300_C2_SEL_A; case PIPE_FORMAT_I8_UNORM: case PIPE_FORMAT_I8_SNORM: case PIPE_FORMAT_L8_UNORM: case PIPE_FORMAT_L8_SNORM: case PIPE_FORMAT_R8_UNORM: case PIPE_FORMAT_R8_SNORM: return modifier | R300_C2_SEL_R; /* X8Y8 * COLORFORMAT_UV88 stores ZX (C2 and C0). */ case PIPE_FORMAT_L8A8_SNORM: case PIPE_FORMAT_L8A8_UNORM: return modifier | R300_C0_SEL_A | R300_C2_SEL_R; case PIPE_FORMAT_R8G8_SNORM: case PIPE_FORMAT_R8G8_UNORM: return modifier | R300_C0_SEL_G | R300_C2_SEL_R; /* X32Y32 * ARGB16161616 stores XZ for RG32F */ case PIPE_FORMAT_R32G32_FLOAT: return modifier | R300_C0_SEL_R | R300_C2_SEL_G; /*** Generic cases (standard channel mapping) ***/ /* BGRA outputs. */ case PIPE_FORMAT_B5G6R5_UNORM: case PIPE_FORMAT_B5G5R5A1_UNORM: case PIPE_FORMAT_B5G5R5X1_UNORM: case PIPE_FORMAT_B4G4R4A4_UNORM: case PIPE_FORMAT_B4G4R4X4_UNORM: case PIPE_FORMAT_B8G8R8A8_UNORM: /*case PIPE_FORMAT_B8G8R8A8_SNORM:*/ case PIPE_FORMAT_B8G8R8X8_UNORM: /*case PIPE_FORMAT_B8G8R8X8_SNORM:*/ case PIPE_FORMAT_B10G10R10A2_UNORM: return modifier | R300_C0_SEL_B | R300_C1_SEL_G | R300_C2_SEL_R | R300_C3_SEL_A; /* ARGB outputs. */ case PIPE_FORMAT_A16_UNORM: case PIPE_FORMAT_A16_SNORM: case PIPE_FORMAT_A16_FLOAT: case PIPE_FORMAT_A32_FLOAT: return modifier | R300_C0_SEL_A | R300_C1_SEL_R | R300_C2_SEL_G | R300_C3_SEL_B; /* RGBA outputs. */ case PIPE_FORMAT_R8G8B8X8_UNORM: /*case PIPE_FORMAT_R8G8B8X8_SNORM:*/ case PIPE_FORMAT_R8G8B8A8_UNORM: case PIPE_FORMAT_R8G8B8A8_SNORM: case PIPE_FORMAT_R10G10B10A2_UNORM: case PIPE_FORMAT_R10G10B10X2_SNORM: case PIPE_FORMAT_R16_UNORM: case PIPE_FORMAT_R16G16_UNORM: case PIPE_FORMAT_R16G16B16A16_UNORM: case PIPE_FORMAT_R16_SNORM: case PIPE_FORMAT_R16G16_SNORM: case PIPE_FORMAT_R16G16B16A16_SNORM: case PIPE_FORMAT_R16_FLOAT: case PIPE_FORMAT_R16G16_FLOAT: case PIPE_FORMAT_R16G16B16A16_FLOAT: case PIPE_FORMAT_R32_FLOAT: case PIPE_FORMAT_R32G32B32A32_FLOAT: case PIPE_FORMAT_L16_UNORM: case PIPE_FORMAT_L16_SNORM: case PIPE_FORMAT_L16_FLOAT: case PIPE_FORMAT_L32_FLOAT: case PIPE_FORMAT_I16_UNORM: case PIPE_FORMAT_I16_SNORM: case PIPE_FORMAT_I16_FLOAT: case PIPE_FORMAT_I32_FLOAT: return modifier | R300_C0_SEL_R | R300_C1_SEL_G | R300_C2_SEL_B | R300_C3_SEL_A; /* LA outputs. */ case PIPE_FORMAT_L16A16_UNORM: case PIPE_FORMAT_L16A16_SNORM: case PIPE_FORMAT_L16A16_FLOAT: case PIPE_FORMAT_L32A32_FLOAT: return modifier | R300_C0_SEL_R | R300_C1_SEL_A; default: return ~0; /* Unsupported. */ } }
/** * Performs blending of src and dst pixels * * @param blend the blend state of the shader variant * @param cbuf_format format of the colour buffer * @param type data type of the pixel vector * @param rt render target index * @param src blend src * @param src_alpha blend src alpha (if not included in src) * @param src1 second blend src (for dual source blend) * @param src1_alpha second blend src alpha (if not included in src1) * @param dst blend dst * @param mask optional mask to apply to the blending result * @param const_ const blend color * @param const_alpha const blend color alpha (if not included in const_) * @param swizzle swizzle values for RGBA * * @return the result of blending src and dst */ LLVMValueRef lp_build_blend_aos(struct gallivm_state *gallivm, const struct pipe_blend_state *blend, enum pipe_format cbuf_format, struct lp_type type, unsigned rt, LLVMValueRef src, LLVMValueRef src_alpha, LLVMValueRef src1, LLVMValueRef src1_alpha, LLVMValueRef dst, LLVMValueRef mask, LLVMValueRef const_, LLVMValueRef const_alpha, const unsigned char swizzle[4], int nr_channels) { const struct pipe_rt_blend_state * state = &blend->rt[rt]; const struct util_format_description * desc; struct lp_build_blend_aos_context bld; LLVMValueRef src_factor, dst_factor; LLVMValueRef result; unsigned alpha_swizzle = UTIL_FORMAT_SWIZZLE_NONE; unsigned i; desc = util_format_description(cbuf_format); /* Setup build context */ memset(&bld, 0, sizeof bld); lp_build_context_init(&bld.base, gallivm, type); bld.src = src; bld.src1 = src1; bld.dst = dst; bld.const_ = const_; bld.src_alpha = src_alpha; bld.src1_alpha = src1_alpha; bld.const_alpha = const_alpha; /* Find the alpha channel if not provided seperately */ if (!src_alpha) { for (i = 0; i < 4; ++i) { if (swizzle[i] == 3) { alpha_swizzle = i; } } } if (blend->logicop_enable) { if(!type.floating) { result = lp_build_logicop(gallivm->builder, blend->logicop_func, src, dst); } else { result = src; } } else if (!state->blend_enable) { result = src; } else { boolean rgb_alpha_same = (state->rgb_src_factor == state->rgb_dst_factor && state->alpha_src_factor == state->alpha_dst_factor) || nr_channels == 1; src_factor = lp_build_blend_factor(&bld, state->rgb_src_factor, state->alpha_src_factor, alpha_swizzle, nr_channels); dst_factor = lp_build_blend_factor(&bld, state->rgb_dst_factor, state->alpha_dst_factor, alpha_swizzle, nr_channels); result = lp_build_blend(&bld.base, state->rgb_func, state->rgb_src_factor, state->rgb_dst_factor, src, dst, src_factor, dst_factor, rgb_alpha_same, false); if(state->rgb_func != state->alpha_func && nr_channels > 1 && alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE) { LLVMValueRef alpha; alpha = lp_build_blend(&bld.base, state->alpha_func, state->alpha_src_factor, state->alpha_dst_factor, src, dst, src_factor, dst_factor, rgb_alpha_same, false); result = lp_build_blend_swizzle(&bld, result, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, nr_channels); } } /* Check if color mask is necessary */ if (!util_format_colormask_full(desc, state->colormask)) { LLVMValueRef color_mask; color_mask = lp_build_const_mask_aos_swizzled(gallivm, bld.base.type, state->colormask, nr_channels, swizzle); lp_build_name(color_mask, "color_mask"); /* Combine with input mask if necessary */ if (mask) { /* We can be blending floating values but masks are always integer... */ unsigned floating = bld.base.type.floating; bld.base.type.floating = 0; mask = lp_build_and(&bld.base, color_mask, mask); bld.base.type.floating = floating; } else { mask = color_mask; } } /* Apply mask, if one exists */ if (mask) { result = lp_build_select(&bld.base, mask, result, dst); } return result; }