This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+1
View File
@@ -0,0 +1 @@
../../../asahi/.clang-format
File diff suppressed because it is too large. Load diff
+664
View File
@@ -0,0 +1,664 @@
/*
* Copyright 2021 Alyssa Rosenzweig
* Copyright 2020-2021 Collabora, Ltd.
* Copyright 2019 Sonny Jiang <[email protected]>
* Copyright 2019 Advanced Micro Devices, Inc.
* Copyright 2014 Broadcom
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include "asahi/compiler/agx_nir_texture.h"
#include "asahi/layout/layout.h"
#include "compiler/nir/nir_builder.h"
#include "compiler/nir/nir_format_convert.h"
#include "gallium/auxiliary/util/u_blitter.h"
#include "gallium/auxiliary/util/u_dump.h"
#include "nir/pipe_nir.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "util/format/u_format.h"
#include "util/format/u_formats.h"
#include "util/hash_table.h"
#include "util/macros.h"
#include "util/ralloc.h"
#include "util/u_sampler.h"
#include "util/u_surface.h"
#include "agx_state.h"
#include "glsl_types.h"
#include "nir.h"
#include "nir_builder_opcodes.h"
#include "shader_enums.h"
/* For block based blit kernels, we hardcode the maximum tile size which we can
* always achieve. This simplifies our life.
*/
#define TILE_WIDTH 32
#define TILE_HEIGHT 32
static enum pipe_format
effective_format(enum pipe_format format)
{
switch (format) {
case PIPE_FORMAT_Z32_FLOAT:
case PIPE_FORMAT_Z24X8_UNORM:
return PIPE_FORMAT_R32_FLOAT;
case PIPE_FORMAT_Z16_UNORM:
return PIPE_FORMAT_R16_UNORM;
case PIPE_FORMAT_S8_UINT:
return PIPE_FORMAT_R8_UINT;
default:
return format;
}
}
static void *
asahi_blit_compute_shader(struct pipe_context *ctx, struct asahi_blit_key *key)
{
const nir_shader_compiler_options *options =
ctx->screen->nir_options[MESA_SHADER_COMPUTE];
nir_builder b_ =
nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, options, "blit_cs");
nir_builder *b = &b_;
b->shader->info.workgroup_size[0] = TILE_WIDTH;
b->shader->info.workgroup_size[1] = TILE_HEIGHT;
b->shader->info.num_ubos = 1;
BITSET_SET(b->shader->info.textures_used, 0);
BITSET_SET(b->shader->info.samplers_used, 0);
BITSET_SET(b->shader->info.images_used, 0);
nir_def *zero = nir_imm_int(b, 0);
nir_def *params[4];
b->shader->num_uniforms = ARRAY_SIZE(params);
for (unsigned i = 0; i < b->shader->num_uniforms; ++i) {
params[i] = nir_load_ubo(b, 2, 32, zero, nir_imm_int(b, i * 8),
.align_mul = 4, .range = ~0);
}
nir_def *trans_offs = params[0];
nir_def *trans_scale = params[1];
nir_def *dst_offs_2d = params[2];
nir_def *dimensions_el_2d = params[3];
nir_def *phys_id_el_nd = nir_trim_vector(
b, nir_load_global_invocation_id(b, 32), key->array ? 3 : 2);
nir_def *phys_id_el_2d = nir_trim_vector(b, phys_id_el_nd, 2);
nir_def *layer = key->array ? nir_channel(b, phys_id_el_nd, 2) : NULL;
/* Offset within the tile. We're dispatched for the entire tile but the
* beginning might be out-of-bounds, so fix up.
*/
nir_def *offs_in_tile_el_2d = nir_iand_imm(b, dst_offs_2d, 31);
nir_def *logical_id_el_2d = nir_isub(b, phys_id_el_2d, offs_in_tile_el_2d);
nir_def *image_pos_2d = nir_iadd(b, logical_id_el_2d, dst_offs_2d);
nir_def *image_pos_nd = image_pos_2d;
if (layer) {
image_pos_nd =
nir_vector_insert_imm(b, nir_pad_vector(b, image_pos_nd, 3), layer, 2);
}
nir_def *in_bounds;
if (key->aligned) {
in_bounds = nir_imm_true(b);
} else {
in_bounds = nir_ige(b, logical_id_el_2d, nir_imm_ivec2(b, 0, 0));
in_bounds =
nir_iand(b, in_bounds, nir_ilt(b, logical_id_el_2d, dimensions_el_2d));
}
unsigned bit_size = 32;
nir_alu_type dst_type = nir_type_uint32;
if (util_format_is_float16(key->dst_format)) {
bit_size = 16;
dst_type = nir_type_float16;
}
nir_def *colour0, *colour1;
nir_push_if(b, nir_ball(b, in_bounds));
{
/* For pixels within the copy area, texture from the source */
nir_def *coords_el_2d =
nir_ffma_weak(b, nir_u2f32(b, logical_id_el_2d), trans_scale, trans_offs);
nir_def *coords_el_nd = coords_el_2d;
if (layer) {
coords_el_nd = nir_vector_insert_imm(
b, nir_pad_vector(b, coords_el_nd, 3), nir_u2f32(b, layer), 2);
}
colour0 = nir_tex(b, coords_el_nd, .texture_index = 0, .sampler_index = 0,
.backend_flags = AGX_TEXTURE_FLAG_NO_CLAMP,
.dim = GLSL_SAMPLER_DIM_2D, .is_array = key->array,
.dest_type = dst_type);
}
nir_push_else(b, NULL);
{
/* For out-of-bounds pixels, copy in the destination */
colour1 = nir_image_load(
b, 4, bit_size, nir_imm_int(b, 0), nir_pad_vec4(b, image_pos_nd), zero, zero,
.image_array = key->array, .image_dim = GLSL_SAMPLER_DIM_2D,
.access = ACCESS_IN_BOUNDS, .dest_type = dst_type);
}
nir_pop_if(b, NULL);
nir_def *color = nir_if_phi(b, colour0, colour1);
enum asahi_blit_clamp clamp = ASAHI_BLIT_CLAMP_NONE;
bool src_sint = util_format_is_pure_sint(key->src_format);
bool dst_sint = util_format_is_pure_sint(key->dst_format);
if (util_format_is_pure_integer(key->src_format) &&
util_format_is_pure_integer(key->dst_format)) {
if (src_sint && !dst_sint)
clamp = ASAHI_BLIT_CLAMP_SINT_TO_UINT;
else if (!src_sint && dst_sint)
clamp = ASAHI_BLIT_CLAMP_UINT_TO_SINT;
}
if (clamp == ASAHI_BLIT_CLAMP_SINT_TO_UINT)
color = nir_imax(b, color, nir_imm_int(b, 0));
else if (clamp == ASAHI_BLIT_CLAMP_UINT_TO_SINT)
color = nir_umin(b, color, nir_imm_int(b, INT32_MAX));
nir_def *local_offset = nir_imm_int(b, 0);
nir_def *lid = nir_trim_vector(b, nir_load_local_invocation_id(b), 2);
lid = nir_u2u16(b, lid);
/* Pure integer formatss need to be clamped in software, at least in some
* cases. We do so on store. Piglit gl-3.0-render-integer checks this, as
* does KHR-GL33.packed_pixels.*.
*
* TODO: Make this common code somehow.
*/
const struct util_format_description *desc =
util_format_description(key->dst_format);
unsigned c = util_format_get_first_non_void_channel(key->dst_format);
if (desc->channel[c].size <= 16 &&
util_format_is_pure_integer(key->dst_format)) {
unsigned bits[4] = {
desc->channel[0].size ?: desc->channel[0].size,
desc->channel[1].size ?: desc->channel[0].size,
desc->channel[2].size ?: desc->channel[0].size,
desc->channel[3].size ?: desc->channel[0].size,
};
if (util_format_is_pure_sint(key->dst_format))
color = nir_format_clamp_sint(b, color, bits);
else
color = nir_format_clamp_uint(b, color, bits);
color = nir_u2u16(b, color);
}
/* The source texel has been converted into a 32-bit value. We need to
* convert it to a tilebuffer format that can then be converted to the
* destination format in the PBE hardware. That's the renderable format for
* the destination format, which must exist along this path. This mirrors the
* flow of fragment and end-of-tile shaders.
*/
enum pipe_format tib_format =
ail_pixel_format[effective_format(key->dst_format)].renderable;
nir_store_local_pixel_agx(b, color, nir_imm_intN_t(b, 1, 16), lid, .base = 0,
.write_mask = 0xf, .format = tib_format,
.explicit_coord = true);
nir_barrier(b, .execution_scope = SCOPE_WORKGROUP);
nir_push_if(b, nir_ball(b, nir_ieq_imm(b, lid, 0)));
{
nir_def *pbe_index = nir_imm_intN_t(b, 2, 16);
nir_image_store_block_agx(
b, pbe_index, local_offset, image_pos_nd, .format = tib_format,
.image_dim = GLSL_SAMPLER_DIM_2D, .image_array = key->array,
.explicit_coord = true);
}
nir_pop_if(b, NULL);
b->shader->info.cs.image_block_size_per_thread_agx =
util_format_get_blocksize(key->dst_format);
return pipe_shader_from_nir(ctx, b->shader);
}
static bool
asahi_compute_blit_supported(const struct pipe_blit_info *info)
{
return (info->src.box.depth == info->dst.box.depth) && !info->alpha_blend &&
!info->num_window_rectangles && !info->sample0_only &&
!info->scissor_enable && !info->window_rectangle_include &&
!info->swizzle_enable && info->src.resource->nr_samples <= 1 &&
info->dst.resource->nr_samples <= 1 &&
!util_format_is_depth_and_stencil(info->src.format) &&
!util_format_is_depth_and_stencil(info->dst.format) &&
info->src.box.depth >= 0 &&
info->mask == util_format_get_mask(info->src.format) &&
/* XXX: texsubimage pbo failing otherwise, needs investigation */
info->dst.format != PIPE_FORMAT_B5G6R5_UNORM &&
info->dst.format != PIPE_FORMAT_B5G5R5A1_UNORM &&
info->dst.format != PIPE_FORMAT_B5G5R5X1_UNORM &&
info->dst.format != PIPE_FORMAT_R5G6B5_UNORM &&
info->dst.format != PIPE_FORMAT_R5G5B5A1_UNORM &&
info->dst.format != PIPE_FORMAT_R5G5B5X1_UNORM;
}
static void
asahi_compute_save(struct agx_context *ctx)
{
struct asahi_blitter *blitter = &ctx->compute_blitter;
struct agx_stage *stage = &ctx->stage[MESA_SHADER_COMPUTE];
assert(!blitter->active && "recursion detected, driver bug");
pipe_resource_reference(&blitter->saved_cb.buffer, stage->cb[0].buffer);
memcpy(&blitter->saved_cb, &stage->cb[0],
sizeof(struct pipe_constant_buffer));
blitter->has_saved_image = stage->image_mask & BITFIELD_BIT(0);
if (blitter->has_saved_image) {
pipe_resource_reference(&blitter->saved_image.resource,
stage->images[0].resource);
memcpy(&blitter->saved_image, &stage->images[0],
sizeof(struct pipe_image_view));
}
pipe_sampler_view_reference(&blitter->saved_sampler_view,
&stage->textures[0]->base);
blitter->saved_num_sampler_states = stage->sampler_count;
memcpy(blitter->saved_sampler_states, stage->samplers,
stage->sampler_count * sizeof(void *));
blitter->saved_cs = stage->shader;
blitter->active = true;
}
static void
asahi_compute_restore(struct agx_context *ctx)
{
struct pipe_context *pctx = &ctx->base;
struct asahi_blitter *blitter = &ctx->compute_blitter;
if (blitter->has_saved_image) {
pctx->set_shader_images(pctx, MESA_SHADER_COMPUTE, 0, 1, 0,
&blitter->saved_image);
pipe_resource_reference(&blitter->saved_image.resource, NULL);
}
/* take_ownership=true so do not unreference */
pctx->set_constant_buffer(pctx, MESA_SHADER_COMPUTE, 0, &blitter->saved_cb);
blitter->saved_cb.buffer = NULL;
if (blitter->saved_sampler_view) {
pctx->set_sampler_views(pctx, MESA_SHADER_COMPUTE, 0, 1, 0,
&blitter->saved_sampler_view);
blitter->saved_sampler_view = NULL;
}
if (blitter->saved_num_sampler_states) {
pctx->bind_sampler_states(pctx, MESA_SHADER_COMPUTE, 0,
blitter->saved_num_sampler_states,
blitter->saved_sampler_states);
}
pctx->bind_compute_state(pctx, blitter->saved_cs);
blitter->saved_cs = NULL;
blitter->active = false;
}
static void
asahi_compute_blit(struct pipe_context *ctx, const struct pipe_blit_info *info,
struct asahi_blitter *blitter)
{
if (info->src.box.width == 0 || info->src.box.height == 0 ||
info->dst.box.width == 0 || info->dst.box.height == 0)
return;
assert(asahi_compute_blit_supported(info));
asahi_compute_save(agx_context(ctx));
unsigned depth = info->dst.box.depth;
bool array = depth > 1;
struct pipe_resource *src = info->src.resource;
struct pipe_resource *dst = info->dst.resource;
struct pipe_sampler_view src_templ = {0}, *src_view;
float src_width = (float)u_minify(src->width0, info->src.level);
float src_height = (float)u_minify(src->height0, info->src.level);
float x_scale =
(info->src.box.width / (float)info->dst.box.width) / src_width;
float y_scale =
(info->src.box.height / (float)info->dst.box.height) / src_height;
/* Expand the grid so destinations are in tiles */
unsigned expanded_x0 = info->dst.box.x & ~(TILE_WIDTH - 1);
unsigned expanded_y0 = info->dst.box.y & ~(TILE_HEIGHT - 1);
unsigned expanded_x1 =
align(info->dst.box.x + info->dst.box.width, TILE_WIDTH);
unsigned expanded_y1 =
align(info->dst.box.y + info->dst.box.height, TILE_HEIGHT);
/* But clamp to the destination size to save some redundant threads */
expanded_x1 =
MIN2(expanded_x1, u_minify(info->dst.resource->width0, info->dst.level));
expanded_y1 =
MIN2(expanded_y1, u_minify(info->dst.resource->height0, info->dst.level));
/* Calculate the width/height based on the expanded grid */
unsigned width = expanded_x1 - expanded_x0;
unsigned height = expanded_y1 - expanded_y0;
unsigned data[] = {
fui(0.5f * x_scale + (float)info->src.box.x / src_width),
fui(0.5f * y_scale + (float)info->src.box.y / src_height),
fui(x_scale),
fui(y_scale),
info->dst.box.x,
info->dst.box.y,
info->dst.box.width,
info->dst.box.height,
};
struct pipe_constant_buffer cb = {
.buffer_size = sizeof(data),
.user_buffer = data,
};
ctx->set_constant_buffer(ctx, MESA_SHADER_COMPUTE, 0, &cb);
struct pipe_image_view image = {
.resource = dst,
.access = PIPE_IMAGE_ACCESS_WRITE | PIPE_IMAGE_ACCESS_DRIVER_INTERNAL,
.shader_access = PIPE_IMAGE_ACCESS_WRITE,
.format = info->dst.format,
.u.tex.level = info->dst.level,
.u.tex.first_layer = info->dst.box.z,
.u.tex.last_layer = info->dst.box.z + depth - 1,
.u.tex.single_layer_view = !array,
};
ctx->set_shader_images(ctx, MESA_SHADER_COMPUTE, 0, 1, 0, &image);
if (!blitter->sampler[info->filter]) {
struct pipe_sampler_state sampler_state = {
.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
.min_img_filter = info->filter,
.mag_img_filter = info->filter,
.compare_func = PIPE_FUNC_ALWAYS,
.seamless_cube_map = true,
.max_lod = 31.0f,
};
blitter->sampler[info->filter] =
ctx->create_sampler_state(ctx, &sampler_state);
}
ctx->bind_sampler_states(ctx, MESA_SHADER_COMPUTE, 0, 1,
&blitter->sampler[info->filter]);
/* Initialize the sampler view. */
u_sampler_view_default_template(&src_templ, src, src->format);
src_templ.format = info->src.format;
src_templ.target = array ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
src_templ.swizzle_r = PIPE_SWIZZLE_X;
src_templ.swizzle_g = PIPE_SWIZZLE_Y;
src_templ.swizzle_b = PIPE_SWIZZLE_Z;
src_templ.swizzle_a = PIPE_SWIZZLE_W;
src_templ.u.tex.first_layer = info->src.box.z;
src_templ.u.tex.last_layer = info->src.box.z + depth - 1;
src_templ.u.tex.first_level = info->src.level;
src_templ.u.tex.last_level = info->src.level;
src_view = ctx->create_sampler_view(ctx, src, &src_templ);
ctx->set_sampler_views(ctx, MESA_SHADER_COMPUTE, 0, 1, 0, &src_view);
ctx->sampler_view_release(ctx, src_view);
struct asahi_blit_key key = {
.src_format = info->src.format,
.dst_format = info->dst.format,
.array = array,
.aligned = info->dst.box.width == width && info->dst.box.height == height,
};
struct hash_entry *ent = _mesa_hash_table_search(blitter->blit_cs, &key);
void *cs = NULL;
if (ent) {
cs = ent->data;
} else {
cs = asahi_blit_compute_shader(ctx, &key);
_mesa_hash_table_insert(
blitter->blit_cs, ralloc_memdup(blitter->blit_cs, &key, sizeof(key)),
cs);
}
assert(cs != NULL);
ctx->bind_compute_state(ctx, cs);
struct pipe_grid_info grid_info = {
.block = {TILE_WIDTH, TILE_HEIGHT, 1},
.last_block = {width % TILE_WIDTH, height % TILE_HEIGHT, 1},
.grid =
{
DIV_ROUND_UP(width, TILE_WIDTH),
DIV_ROUND_UP(height, TILE_HEIGHT),
depth,
},
};
ctx->launch_grid(ctx, &grid_info);
ctx->set_shader_images(ctx, MESA_SHADER_COMPUTE, 0, 0, 1, NULL);
ctx->set_constant_buffer(ctx, MESA_SHADER_COMPUTE, 0, NULL);
ctx->set_sampler_views(ctx, MESA_SHADER_COMPUTE, 0, 0, 1, NULL);
asahi_compute_restore(agx_context(ctx));
}
void
agx_blitter_save(struct agx_context *ctx, struct blitter_context *blitter,
enum asahi_blitter_op op)
{
util_blitter_save_vertex_shader(blitter,
ctx->stage[MESA_SHADER_VERTEX].shader);
util_blitter_save_tessctrl_shader(blitter,
ctx->stage[MESA_SHADER_TESS_CTRL].shader);
util_blitter_save_tesseval_shader(blitter,
ctx->stage[MESA_SHADER_TESS_EVAL].shader);
util_blitter_save_geometry_shader(blitter,
ctx->stage[MESA_SHADER_GEOMETRY].shader);
util_blitter_save_so_targets(blitter, ctx->streamout.num_targets,
ctx->streamout.targets, MESA_PRIM_UNKNOWN);
util_blitter_save_vertex_buffers(blitter, ctx->vertex_buffers,
util_last_bit(ctx->vb_mask));
util_blitter_save_vertex_elements(blitter, ctx->attributes);
util_blitter_save_rasterizer(blitter, ctx->rast);
util_blitter_save_viewport(blitter, &ctx->viewport[0]);
if (op & ASAHI_SAVE_FRAGMENT_STATE) {
util_blitter_save_blend(blitter, ctx->blend);
util_blitter_save_depth_stencil_alpha(blitter, ctx->zs);
util_blitter_save_stencil_ref(blitter, &ctx->stencil_ref);
util_blitter_save_sample_mask(blitter, ctx->sample_mask, 0);
util_blitter_save_scissor(blitter, &ctx->scissor[0]);
util_blitter_save_fragment_shader(
blitter, ctx->stage[MESA_SHADER_FRAGMENT].shader);
if (op & ASAHI_SAVE_FRAGMENT_CONSTANT) {
util_blitter_save_fragment_constant_buffer_slot(
blitter, ctx->stage[MESA_SHADER_FRAGMENT].cb);
}
}
if (op & ASAHI_SAVE_FRAMEBUFFER) {
util_blitter_save_framebuffer(blitter, &ctx->framebuffer);
}
if (op & ASAHI_SAVE_TEXTURES) {
util_blitter_save_fragment_sampler_states(
blitter, ctx->stage[MESA_SHADER_FRAGMENT].sampler_count,
(void **)(ctx->stage[MESA_SHADER_FRAGMENT].samplers));
util_blitter_save_fragment_sampler_views(
blitter, ctx->stage[MESA_SHADER_FRAGMENT].texture_count,
(struct pipe_sampler_view **)ctx->stage[MESA_SHADER_FRAGMENT].textures);
}
if (!(op & ASAHI_DISABLE_RENDER_COND)) {
util_blitter_save_render_condition(blitter,
(struct pipe_query *)ctx->cond_query,
ctx->cond_cond, ctx->cond_mode);
}
}
void
agx_blit(struct pipe_context *pipe, const struct pipe_blit_info *info)
{
struct agx_context *ctx = agx_context(pipe);
if (info->render_condition_enable && !agx_render_condition_check(ctx))
return;
/* Legalize compression /before/ calling into u_blitter to avoid recursion.
* u_blitter bans recursive usage.
*/
agx_legalize_compression(ctx, agx_resource(info->dst.resource),
info->dst.format);
agx_legalize_compression(ctx, agx_resource(info->src.resource),
info->src.format);
if (asahi_compute_blit_supported(info)) {
asahi_compute_blit(pipe, info, &ctx->compute_blitter);
return;
}
if (!util_blitter_is_blit_supported(ctx->blitter, info)) {
fprintf(stderr, "\n");
util_dump_blit_info(stderr, info);
fprintf(stderr, "\n\n");
UNREACHABLE("Unsupported blit");
}
/* Handle self-blits */
agx_flush_writer(ctx, agx_resource(info->dst.resource), "Blit");
agx_blitter_save(
ctx, ctx->blitter,
ASAHI_BLIT |
(info->render_condition_enable ? 0 : ASAHI_DISABLE_RENDER_COND));
util_blitter_blit(ctx->blitter, info, NULL);
}
static bool
try_copy_via_blit(struct pipe_context *pctx, 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 agx_context *ctx = agx_context(pctx);
if (dst->target == PIPE_BUFFER)
return false;
/* TODO: Handle these for rusticl copies */
if (dst->target != src->target)
return false;
struct pipe_blit_info info = {
.dst =
{
.resource = dst,
.level = dst_level,
.box.x = dstx,
.box.y = dsty,
.box.z = dstz,
.box.width = src_box->width,
.box.height = src_box->height,
.box.depth = src_box->depth,
.format = dst->format,
},
.src =
{
.resource = src,
.level = src_level,
.box = *src_box,
.format = src->format,
},
.mask = util_format_get_mask(src->format),
.filter = PIPE_TEX_FILTER_NEAREST,
.scissor_enable = 0,
.swizzle_enable = 0,
};
/* snorm formats don't round trip, so don't use them for copies */
if (util_format_is_snorm(info.dst.format))
info.dst.format = util_format_snorm_to_sint(info.dst.format);
if (util_format_is_snorm(info.src.format))
info.src.format = util_format_snorm_to_sint(info.src.format);
if (util_blitter_is_blit_supported(ctx->blitter, &info) &&
info.dst.format == info.src.format) {
agx_blit(pctx, &info);
return true;
} else {
return false;
}
}
void
agx_resource_copy_region(struct pipe_context *pctx, 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)
{
if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
struct agx_batch *batch = agx_get_compute_batch(agx_context(pctx));
agx_batch_init_state(batch);
assert(dst->format == src->format);
unsigned bs = util_format_get_blocksize(dst->format);
unsigned size = bs * src_box->width;
unsigned dst_offset = dstx * bs;
uint64_t dst_addr = agx_map_gpu(agx_resource(dst)) + dst_offset;
uint64_t src_addr = agx_map_gpu(agx_resource(src)) + src_box->x * bs;
agx_batch_reads(batch, agx_resource(src));
agx_batch_writes_range(batch, agx_resource(dst), dst_offset, size);
/* Use vectorized copies for as much of the buffer as possible. This requires
* that dst, src, and size are all properly aligned. Failing to check for
* alignment on the buffers causes subtle and hard-to-debug issues!
*/
if (size >= 16 && (dst_addr & 0xf) == 0 && (src_addr & 0xf) == 0) {
unsigned uint4s = size / 16;
unsigned bytes = uint4s * 16;
libagx_copy_uint4(batch, agx_1d(uint4s), AGX_BARRIER_ALL, dst_addr, src_addr);
dst_addr += bytes;
src_addr += bytes;
size -= bytes;
}
if (size) {
libagx_copy_uchar(batch, agx_1d(size), AGX_BARRIER_ALL, dst_addr, src_addr);
}
return;
}
if (try_copy_via_blit(pctx, dst, dst_level, dstx, dsty, dstz, src, src_level,
src_box))
return;
/* CPU fallback */
util_resource_copy_region(pctx, dst, dst_level, dstx, dsty, dstz, src,
src_level, src_box);
}
+224
View File
@@ -0,0 +1,224 @@
/*
* Copyright 2023 Rose Hudson
* Copyright 2022 Amazon.com, Inc. or its affiliates.
* Copyright 2018 Intel Corporation
* SPDX-License-Identifier: MIT
*/
#include <assert.h>
#include <stdio.h>
#include "asahi/compiler/agx_debug.h"
#include "compiler/shader_enums.h"
#include "util/blob.h"
#include "util/build_id.h"
#include "util/disk_cache.h"
#include "util/mesa-blake3.h"
#include "agx_bo.h"
#include "agx_device.h"
#include "agx_disk_cache.h"
#include "agx_state.h"
/* Flags that are allowed and do not disable the disk cache */
#define ALLOWED_FLAGS (AGX_DBG_NO16)
/**
* Compute a disk cache key for the given uncompiled shader and shader key.
*/
static void
agx_disk_cache_compute_key(struct disk_cache *cache,
const struct agx_uncompiled_shader *uncompiled,
const union asahi_shader_key *shader_key,
cache_key cache_key)
{
uint8_t data[sizeof(uncompiled->nir_blake3) + sizeof(*shader_key)];
int hash_size = sizeof(uncompiled->nir_blake3);
int key_size;
if (uncompiled->type == MESA_SHADER_VERTEX ||
uncompiled->type == MESA_SHADER_TESS_EVAL)
key_size = sizeof(shader_key->vs);
else if (uncompiled->type == MESA_SHADER_FRAGMENT)
key_size = sizeof(shader_key->fs);
else
key_size = 0;
memcpy(data, uncompiled->nir_blake3, hash_size);
if (key_size)
memcpy(data + hash_size, shader_key, key_size);
disk_cache_compute_key(cache, data, hash_size + key_size, cache_key);
}
static void
write_shader(struct blob *blob, const struct agx_compiled_shader *binary,
bool is_root_gs)
{
blob_write_bytes(blob, &binary->b.info, sizeof(binary->b.info));
if (binary->b.info.binary_size) {
blob_write_bytes(blob, binary->b.binary, binary->b.info.binary_size);
}
blob_write_bytes(blob, &binary->uvs, sizeof(binary->uvs));
blob_write_bytes(blob, &binary->attrib_components_read,
sizeof(binary->attrib_components_read));
blob_write_bytes(blob, &binary->epilog_key, sizeof(binary->epilog_key));
blob_write_uint32(blob, binary->push_range_count);
blob_write_bytes(blob, binary->push,
sizeof(binary->push[0]) * binary->push_range_count);
if (is_root_gs) {
blob_write_bytes(blob, &binary->gs, sizeof(binary->gs));
write_shader(blob, binary->pre_gs, false);
blob_write_uint8(blob, binary->gs_copy != NULL);
if (binary->gs_copy)
write_shader(blob, binary->gs_copy, false);
blob_write_uint8(blob, binary->gs_count != NULL);
if (binary->gs_count)
write_shader(blob, binary->gs_count, false);
}
}
static struct agx_compiled_shader *
read_shader(struct agx_screen *screen, struct blob_reader *blob,
const struct agx_uncompiled_shader *uncompiled, bool is_root)
{
struct agx_compiled_shader *binary = CALLOC_STRUCT(agx_compiled_shader);
binary->stage = uncompiled->type;
binary->so = uncompiled;
blob_copy_bytes(blob, &binary->b.info, sizeof(binary->b.info));
size_t size = binary->b.info.binary_size;
if (uncompiled->type == MESA_SHADER_VERTEX ||
uncompiled->type == MESA_SHADER_TESS_EVAL ||
uncompiled->type == MESA_SHADER_FRAGMENT) {
binary->b.binary = malloc(size);
blob_copy_bytes(blob, binary->b.binary, size);
if (size) {
binary->bo = agx_bo_create(&screen->dev, size, 0,
AGX_BO_EXEC | AGX_BO_LOW_VA, "Executable");
memcpy(agx_bo_map(binary->bo), binary->b.binary, size);
}
} else if (size) {
binary->bo = agx_bo_create(&screen->dev, size, 0,
AGX_BO_EXEC | AGX_BO_LOW_VA, "Executable");
blob_copy_bytes(blob, agx_bo_map(binary->bo), size);
}
blob_copy_bytes(blob, &binary->uvs, sizeof(binary->uvs));
blob_copy_bytes(blob, &binary->attrib_components_read,
sizeof(binary->attrib_components_read));
blob_copy_bytes(blob, &binary->epilog_key, sizeof(binary->epilog_key));
binary->push_range_count = blob_read_uint32(blob);
blob_copy_bytes(blob, binary->push,
sizeof(binary->push[0]) * binary->push_range_count);
if (is_root && uncompiled->type == MESA_SHADER_GEOMETRY) {
blob_copy_bytes(blob, &binary->gs, sizeof(binary->gs));
binary->pre_gs = read_shader(screen, blob, uncompiled, false);
if (blob_read_uint8(blob))
binary->gs_copy = read_shader(screen, blob, uncompiled, false);
if (blob_read_uint8(blob))
binary->gs_count = read_shader(screen, blob, uncompiled, false);
}
return binary;
}
/**
* Store the given compiled shader in the disk cache.
*
* This should only be called on newly compiled shaders. No checking is
* done to prevent repeated stores of the same shader.
*/
void
agx_disk_cache_store(struct disk_cache *cache,
const struct agx_uncompiled_shader *uncompiled,
const union asahi_shader_key *key,
const struct agx_compiled_shader *binary)
{
#ifdef ENABLE_SHADER_CACHE
if (!cache)
return;
cache_key cache_key;
agx_disk_cache_compute_key(cache, uncompiled, key, cache_key);
struct blob blob;
blob_init(&blob);
write_shader(&blob, binary, uncompiled->type == MESA_SHADER_GEOMETRY);
disk_cache_put(cache, cache_key, blob.data, blob.size, NULL);
blob_finish(&blob);
#endif
}
/**
* Search for a compiled shader in the disk cache.
*/
struct agx_compiled_shader *
agx_disk_cache_retrieve(struct agx_screen *screen,
const struct agx_uncompiled_shader *uncompiled,
const union asahi_shader_key *key)
{
#ifdef ENABLE_SHADER_CACHE
struct disk_cache *cache = screen->disk_cache;
if (!cache)
return NULL;
cache_key cache_key;
agx_disk_cache_compute_key(cache, uncompiled, key, cache_key);
size_t size;
void *buffer = disk_cache_get(cache, cache_key, &size);
if (!buffer)
return NULL;
struct blob_reader blob;
blob_reader_init(&blob, buffer, size);
struct agx_compiled_shader *binary =
read_shader(screen, &blob, uncompiled, true);
free(buffer);
return binary;
#else
return NULL;
#endif
}
/**
* Initialise the on-disk shader cache.
*/
void
agx_disk_cache_init(struct agx_screen *screen)
{
#ifdef ENABLE_SHADER_CACHE
if (agx_get_compiler_debug() || (screen->dev.debug & ~ALLOWED_FLAGS))
return;
const char *renderer = screen->pscreen.get_name(&screen->pscreen);
const struct build_id_note *note =
build_id_find_nhdr_for_addr(agx_disk_cache_init);
assert(note && build_id_length(note) == BUILD_ID_EXPECTED_HASH_LENGTH);
const uint8_t *id_sha1 = build_id_data(note);
assert(id_sha1);
char timestamp[BLAKE3_HEX_LEN];
_mesa_sha1_format(timestamp, id_sha1);
uint64_t driver_flags = screen->dev.debug;
screen->disk_cache = disk_cache_create(renderer, timestamp, driver_flags);
#endif
}
@@ -0,0 +1,23 @@
/*
* Copyright 2023 Rose Hudson
* Copyright 2018 Alyssa Rosenzweig
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "util/disk_cache.h"
#include "agx_state.h"
void agx_disk_cache_store(struct disk_cache *cache,
const struct agx_uncompiled_shader *uncompiled,
const union asahi_shader_key *key,
const struct agx_compiled_shader *binary);
struct agx_compiled_shader *
agx_disk_cache_retrieve(struct agx_screen *screen,
const struct agx_uncompiled_shader *uncompiled,
const union asahi_shader_key *key);
void agx_disk_cache_init(struct agx_screen *screen);
+163
View File
@@ -0,0 +1,163 @@
/*
* Based on panfrost/pan_fence.c:
*
* Copyright 2022 Amazon.com, Inc. or its affiliates.
* Copyright 2008 VMware, Inc.
* Copyright 2014 Broadcom
* Copyright 2018 Alyssa Rosenzweig
* Copyright 2019 Collabora, Ltd.
* Copyright 2012 Rob Clark
* SPDX-License-Identifier: MIT
*/
#include <xf86drm.h>
#include "agx_fence.h"
#include "agx_state.h"
#include "util/libsync.h"
#include "util/os_time.h"
#include "util/u_inlines.h"
void
agx_fence_reference(struct pipe_screen *pscreen, struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
struct agx_device *dev = agx_device(pscreen);
struct pipe_fence_handle *old = *ptr;
if (pipe_reference(old ? &old->reference : NULL,
fence ? &fence->reference : NULL)) {
drmSyncobjDestroy(dev->fd, old->syncobj);
free(old);
}
*ptr = fence;
}
bool
agx_fence_finish(struct pipe_screen *pscreen, struct pipe_context *ctx,
struct pipe_fence_handle *fence, uint64_t timeout)
{
struct agx_device *dev = agx_device(pscreen);
int ret;
if (fence->signaled)
return true;
uint64_t abs_timeout = os_time_get_absolute_timeout(timeout);
if (abs_timeout == OS_TIMEOUT_INFINITE)
abs_timeout = INT64_MAX;
ret = drmSyncobjWait(dev->fd, &fence->syncobj, 1, abs_timeout,
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, NULL);
assert(ret >= 0 || ret == -ETIME);
fence->signaled = (ret >= 0);
return fence->signaled;
}
int
agx_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *f)
{
struct agx_device *dev = agx_device(screen);
int fd = -1;
int ret = drmSyncobjExportSyncFile(dev->fd, f->syncobj, &fd);
assert(ret >= 0);
assert(fd >= 0);
return fd;
}
struct pipe_fence_handle *
agx_fence_from_fd(struct agx_context *ctx, int fd, enum pipe_fd_type type)
{
struct agx_device *dev = agx_device(ctx->base.screen);
int ret;
struct pipe_fence_handle *f = calloc(1, sizeof(*f));
if (!f)
return NULL;
if (type == PIPE_FD_TYPE_NATIVE_SYNC) {
ret = drmSyncobjCreate(dev->fd, 0, &f->syncobj);
if (ret) {
agx_msg("create syncobj failed\n");
goto err_free_fence;
}
ret = drmSyncobjImportSyncFile(dev->fd, f->syncobj, fd);
if (ret) {
agx_msg("import syncfile failed\n");
goto err_destroy_syncobj;
}
} else {
assert(type == PIPE_FD_TYPE_SYNCOBJ);
ret = drmSyncobjFDToHandle(dev->fd, fd, &f->syncobj);
if (ret) {
agx_msg("import syncobj FD failed\n");
goto err_free_fence;
}
}
pipe_reference_init(&f->reference, 1);
return f;
err_destroy_syncobj:
drmSyncobjDestroy(dev->fd, f->syncobj);
err_free_fence:
free(f);
return NULL;
}
struct pipe_fence_handle *
agx_fence_create(struct agx_context *ctx)
{
struct agx_device *dev = agx_device(ctx->base.screen);
int fd = -1, ret;
/* Snapshot the last rendering out fence. We'd rather have another
* syncobj instead of a sync file, but this is all we get.
* (HandleToFD/FDToHandle just gives you another syncobj ID for the
* same syncobj).
*/
ret = drmSyncobjExportSyncFile(dev->fd, ctx->syncobj, &fd);
assert(ret >= 0 && fd != -1 && "export failed");
if (ret || fd == -1) {
agx_msg("export failed\n");
return NULL;
}
struct pipe_fence_handle *f =
agx_fence_from_fd(ctx, fd, PIPE_FD_TYPE_NATIVE_SYNC);
close(fd);
return f;
}
void
agx_create_fence_fd(struct pipe_context *pctx,
struct pipe_fence_handle **pfence, int fd,
enum pipe_fd_type type)
{
*pfence = agx_fence_from_fd(agx_context(pctx), fd, type);
}
void
agx_fence_server_sync(struct pipe_context *pctx, struct pipe_fence_handle *f,
uint64_t value)
{
struct agx_device *dev = agx_device(pctx->screen);
struct agx_context *ctx = agx_context(pctx);
int fd = -1, ret;
assert(!value);
ret = drmSyncobjExportSyncFile(dev->fd, f->syncobj, &fd);
assert(!ret);
sync_accumulate("asahi", &ctx->in_sync_fd, fd);
close(fd);
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates.
* Copyright 2018-2019 Alyssa Rosenzweig
* Copyright 2018-2019 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "pipe/p_state.h"
struct agx_context;
struct pipe_fence_handle {
struct pipe_reference reference;
uint32_t syncobj;
bool signaled;
};
void agx_fence_reference(struct pipe_screen *pscreen,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence);
bool agx_fence_finish(struct pipe_screen *pscreen, struct pipe_context *ctx,
struct pipe_fence_handle *fence, uint64_t timeout);
int agx_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *f);
struct pipe_fence_handle *agx_fence_from_fd(struct agx_context *ctx, int fd,
enum pipe_fd_type type);
struct pipe_fence_handle *agx_fence_create(struct agx_context *ctx);
void agx_create_fence_fd(struct pipe_context *pctx,
struct pipe_fence_handle **pfence, int fd,
enum pipe_fd_type type);
void agx_fence_server_sync(struct pipe_context *pctx,
struct pipe_fence_handle *f, uint64_t value);
@@ -0,0 +1,160 @@
/*
* Copyright 2023 Valve Corporation
* SPDX-License-Identifier: MIT
*/
#include "asahi/compiler/agx_nir.h"
#include "compiler/nir/nir_builder.h"
#include "util/bitset.h"
#include "agx_state.h"
#include "nir.h"
#include "nir_builder_opcodes.h"
#include "nir_intrinsics.h"
#include "nir_intrinsics_indices.h"
/*
* Lower binding table textures and images to texture state registers and (if
* necessary) bindless access into an internal table mapped like additional
* texture state registers. The following layout is used:
*
* 1. Textures
* 2. Images (read/write interleaved)
*/
static bool
lower_sampler(nir_builder *b, nir_tex_instr *tex)
{
if (!nir_tex_instr_need_sampler(tex))
return false;
nir_def *index = nir_steal_tex_src(tex, nir_tex_src_sampler_offset);
if (!index)
index = nir_imm_int(b, tex->sampler_index);
nir_tex_instr_add_src(tex, nir_tex_src_sampler_handle,
nir_load_sampler_handle_agx(b, index));
return true;
}
static bool
lower(nir_builder *b, nir_instr *instr, void *data)
{
bool *uses_bindless_samplers = data;
bool progress = false;
bool force_bindless = agx_nir_needs_texture_crawl(instr);
b->cursor = nir_before_instr(instr);
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_image_load:
case nir_intrinsic_image_store:
case nir_intrinsic_image_size:
case nir_intrinsic_image_samples:
case nir_intrinsic_image_atomic:
case nir_intrinsic_image_atomic_swap:
break;
default:
return false;
}
nir_def *index = intr->src[0].ssa;
nir_scalar index_scalar = nir_scalar_resolved(index, 0);
/* Remap according to the driver layout */
unsigned offset = BITSET_LAST_BIT(b->shader->info.textures_used);
/* For reads and queries, we use the texture descriptor which is first.
* Writes and atomics use the PBE descriptor.
*/
if (intr->intrinsic != nir_intrinsic_image_load &&
intr->intrinsic != nir_intrinsic_image_size &&
intr->intrinsic != nir_intrinsic_image_samples)
offset++;
/* If we can determine statically that the image fits in texture state
* registers, avoid lowering to bindless access.
*/
if (nir_scalar_is_const(index_scalar) && !force_bindless) {
unsigned idx = (nir_scalar_as_uint(index_scalar) * 2) + offset;
if (idx < AGX_NUM_TEXTURE_STATE_REGS) {
nir_src_rewrite(&intr->src[0], nir_imm_intN_t(b, idx, 16));
return true;
}
}
/* Otherwise, lower to bindless...
*
* The driver uploads enough null texture/PBE descriptors for robustness
* given the shader limit, but we still need to clamp since we're lowering
* to bindless so the hardware doesn't know the limit.
*
* The GL spec says out-of-bounds image indexing is undefined, but
* faulting is not acceptable for robustness.
*/
index = nir_umin(
b, index,
nir_imm_intN_t(b, b->shader->info.num_images - 1, index->bit_size));
index = nir_iadd_imm(b, nir_imul_imm(b, index, 2), offset);
nir_rewrite_image_intrinsic(intr, nir_load_texture_handle_agx(b, index),
nir_image_intrinsic_type_bindless);
} else if (instr->type == nir_instr_type_tex) {
nir_tex_instr *tex = nir_instr_as_tex(instr);
if (((BITSET_COUNT(b->shader->info.samplers_used) > 16) &&
(nir_tex_instr_src_index(tex, nir_tex_src_sampler_offset) >= 0 ||
tex->sampler_index >= 16)) &&
lower_sampler(b, tex)) {
progress = true;
*uses_bindless_samplers = true;
}
/* Nothing to do for "real" bindless */
if (nir_tex_instr_src_index(tex, nir_tex_src_texture_handle) >= 0)
return progress;
/* Textures are mapped 1:1, so if we can prove it fits in a texture state
* register, use the texture state register.
*/
if (tex->texture_index < AGX_NUM_TEXTURE_STATE_REGS &&
nir_tex_instr_src_index(tex, nir_tex_src_texture_offset) == -1 &&
!force_bindless)
return progress;
/* Otherwise, lower to bindless. Could be optimized. */
nir_def *index = nir_steal_tex_src(tex, nir_tex_src_texture_offset);
if (!index)
index = nir_imm_int(b, tex->texture_index);
/* As above */
index = nir_umin(
b, index,
nir_imm_intN_t(b, b->shader->info.num_textures - 1, index->bit_size));
nir_tex_instr_add_src(tex, nir_tex_src_texture_handle,
nir_load_texture_handle_agx(b, index));
}
return true;
}
bool
agx_nir_lower_bindings(nir_shader *shader, bool *uses_bindless_samplers)
{
/* First lower index to offset so we can lower more naturally */
bool progress = nir_lower_tex(
shader, &(nir_lower_tex_options){.lower_index_to_offset = true});
/* Next run constant folding so the constant optimizations above have a
* chance.
*/
progress |= nir_opt_constant_folding(shader);
progress |= nir_shader_instructions_pass(
shader, lower, nir_metadata_control_flow, uses_bindless_samplers);
return progress;
}
@@ -0,0 +1,62 @@
/*
* Copyright 2023 Valve Corporation
* SPDX-License-Identifier: MIT
*/
#include "agx_state.h"
#include "nir.h"
#include "nir_builder.h"
#include "nir_builder_opcodes.h"
/*
* gl_PointSize lowering. This runs late on a vertex shader. By this time, I/O
* has been lowered, and transform feedback has been written. Point size will
* thus only get consumed by the rasterizer, so we can clamp/replace. We do
* this instead of the mesa/st lowerings to avoid the variant. I wouldn't mind
* ripping this out some day...
*/
static bool
pass(nir_builder *b, nir_intrinsic_instr *intr, void *data)
{
b->cursor = nir_before_instr(&intr->instr);
if ((intr->intrinsic != nir_intrinsic_store_output) ||
(nir_intrinsic_io_semantics(intr).location != VARYING_SLOT_PSIZ))
return false;
/* The size we write must be clamped */
nir_def *size = nir_fmax(b, intr->src[0].ssa, nir_imm_float(b, 1.0f));
/* Override it if the API requires */
nir_def *fixed_size = nir_load_fixed_point_size_agx(b);
size = nir_bcsel(b, nir_fgt_imm(b, fixed_size, 0.0), fixed_size, size);
nir_src_rewrite(&intr->src[0], size);
return true;
}
bool
agx_nir_lower_point_size(nir_shader *nir, bool insert_write)
{
/* Lower existing point size write */
if (nir_shader_intrinsics_pass(nir, pass, nir_metadata_control_flow, NULL))
return true;
if (!insert_write)
return false;
/* If there's no existing point size write, insert one. This assumes there
* was a fixed point size set in the API. If not, GL allows undefined
* behaviour, which we implement by writing garbage.
*/
nir_builder b =
nir_builder_at(nir_after_impl(nir_shader_get_entrypoint(nir)));
nir_store_output(
&b, nir_load_fixed_point_size_agx(&b), nir_imm_int(&b, 0),
.io_semantics.location = VARYING_SLOT_PSIZ, .io_semantics.num_slots = 1,
.write_mask = nir_component_mask(1), .src_type = nir_type_float32);
nir->info.outputs_written |= VARYING_BIT_PSIZ;
return nir_progress(true, b.impl, nir_metadata_control_flow);
}
@@ -0,0 +1,525 @@
/*
* Copyright 2022 Alyssa Rosenzweig
* SPDX-License-Identifier: MIT
*/
#include "compiler/nir/nir_builder.h"
#include "pipe/p_defines.h"
#include "poly/nir/poly_nir.h"
#include "util/bitset.h"
#include "util/u_dynarray.h"
#include "agx_abi.h"
#include "agx_state.h"
#include "nir.h"
#include "nir_builder_opcodes.h"
#include "nir_intrinsics.h"
#include "nir_intrinsics_indices.h"
#include "shader_enums.h"
#define AGX_TEXTURE_DESC_STRIDE 24
/*
* Lower all system values to uniform loads. This pass tries to compact ranges
* of contiguous uploaded uniforms to reduce the draw-time overhead of uploading
* many tiny ranges. To do so, it works in 4 steps:
*
* 1. Lower NIR sysvals to loads from the system value buffers.
* 2. Walk the NIR, recording loads from system value buffers.
* 2. Walk the ranges of uniforms needed, compacting into contiguous ranges.
* 3. Fill in the load_preamble instructions with the real uniforms.
*/
#define MAX_TABLE_SIZE sizeof(struct agx_stage_uniforms)
static_assert(sizeof(struct agx_draw_uniforms) <= MAX_TABLE_SIZE, "packed");
struct table_state {
/* Bitset of 16-bit uniforms pushed */
BITSET_DECLARE(pushed, MAX_TABLE_SIZE / 2);
/* Element size in 16-bit units, so we may split ranges of different sizes
* to guarantee natural alignment.
*/
uint8_t element_size[MAX_TABLE_SIZE / 2];
};
struct state {
mesa_shader_stage stage, hw_stage;
/* Array of nir_intrinsic_instr's to fix up at the end */
struct util_dynarray loads;
struct table_state tables[AGX_NUM_SYSVAL_TABLES];
};
static nir_def *
load_sysval(nir_builder *b, unsigned dim, unsigned bitsize, uint8_t table,
uint16_t offset)
{
return nir_load_sysval_agx(b, dim, bitsize, .desc_set = table,
.binding = offset);
}
static nir_def *
load_sysval_root(nir_builder *b, unsigned dim, unsigned bitsize, void *ptr)
{
return load_sysval(b, dim, bitsize, AGX_SYSVAL_TABLE_ROOT, (uintptr_t)ptr);
}
static nir_def *
load_sysval_indirect(nir_builder *b, unsigned dim, unsigned bitsize,
uint8_t table, void *base, nir_def *offset_el)
{
nir_scalar scalar = {offset_el, 0};
unsigned stride = (dim * bitsize) / 8;
if (nir_scalar_is_const(scalar)) {
/* Load the sysval directly */
return load_sysval(
b, dim, bitsize, table,
(uintptr_t)base + (nir_scalar_as_uint(scalar) * stride));
} else {
/* Load the base address of the table */
struct agx_draw_uniforms *u = NULL;
nir_def *table_base = load_sysval_root(b, 1, 64, &u->tables[table]);
/* Load address of the array in the table */
nir_def *array_base = nir_iadd_imm(b, table_base, (uintptr_t)base);
/* Index into the table and load */
nir_def *address = nir_iadd(
b, array_base, nir_u2u64(b, nir_imul_imm(b, offset_el, stride)));
return nir_load_global_constant(b, dim, bitsize, address);
}
}
static unsigned
stage_table(nir_builder *b)
{
mesa_shader_stage stage = b->shader->info.stage;
if (stage == MESA_SHADER_VERTEX && b->shader->info.vs.tes_poly)
stage = MESA_SHADER_TESS_EVAL;
assert(stage < MESA_SHADER_STAGES);
return AGX_SYSVAL_STAGE(stage);
}
static nir_def *
load_ubo(nir_builder *b, nir_intrinsic_instr *intr, void *bases)
{
nir_def *base =
load_sysval_indirect(b, 1, 64, stage_table(b), bases, intr->src[0].ssa);
nir_def *address = nir_iadd(b, base, nir_u2u64(b, intr->src[1].ssa));
return nir_load_global_constant(b, intr->num_components, intr->def.bit_size,
address,
.align_mul = nir_intrinsic_align(intr));
}
static nir_def *
load_texture_handle(nir_builder *b, nir_intrinsic_instr *intr, void *base)
{
nir_def *offs_B =
nir_imul_imm(b, nir_u2u32(b, intr->src[0].ssa), AGX_TEXTURE_DESC_STRIDE);
nir_load_sysval_agx(b, 1, 64, .desc_set = stage_table(b),
.binding = (uintptr_t)base, .flags = ~0);
return nir_bindless_image_agx(b, offs_B);
}
static nir_def *
load_provoking_vtx(nir_builder *b)
{
struct agx_draw_uniforms *u = NULL;
return load_sysval_root(b, 1, 16, &u->provoking_vertex);
}
static nir_def *
lower_intrinsic(nir_builder *b, nir_intrinsic_instr *intr,
bool lower_draw_params)
{
struct agx_draw_uniforms *u = NULL;
struct agx_stage_uniforms *s = NULL;
switch (intr->intrinsic) {
case nir_intrinsic_load_ubo:
return load_ubo(b, intr, s->ubo_base);
case nir_intrinsic_load_texture_handle_agx:
return load_texture_handle(b, intr, &s->texture_base);
case nir_intrinsic_load_sampler_handle_agx:
return load_sysval_indirect(b, 1, 16, stage_table(b), &s->sampler_handle,
intr->src[0].ssa);
case nir_intrinsic_load_vbo_base_agx:
return load_sysval_indirect(b, 1, 64, AGX_SYSVAL_TABLE_ROOT,
&u->attrib_base, intr->src[0].ssa);
case nir_intrinsic_load_attrib_clamp_agx:
return load_sysval_indirect(b, 1, 32, AGX_SYSVAL_TABLE_ROOT,
&u->attrib_clamp, intr->src[0].ssa);
case nir_intrinsic_load_blend_const_color_r_float:
return load_sysval_root(b, 1, 32, &u->blend_constant[0]);
case nir_intrinsic_load_blend_const_color_g_float:
return load_sysval_root(b, 1, 32, &u->blend_constant[1]);
case nir_intrinsic_load_blend_const_color_b_float:
return load_sysval_root(b, 1, 32, &u->blend_constant[2]);
case nir_intrinsic_load_blend_const_color_a_float:
return load_sysval_root(b, 1, 32, &u->blend_constant[3]);
case nir_intrinsic_load_api_sample_mask_agx:
return load_sysval_root(b, 1, 16, &u->sample_mask);
case nir_intrinsic_load_sample_positions_agx:
return load_sysval_root(b, 1, 32, &u->ppp_multisamplectl);
case nir_intrinsic_load_stat_query_address_poly:
return load_sysval_root(
b, 1, 64, &u->pipeline_statistics[nir_intrinsic_base(intr)]);
case nir_intrinsic_load_ssbo_address:
assert(nir_src_as_uint(intr->src[1]) == 0);
return load_sysval_indirect(b, 1, 64, stage_table(b), &s->ssbo_base,
intr->src[0].ssa);
case nir_intrinsic_get_ubo_size:
return load_sysval_indirect(b, 1, 32, stage_table(b), &s->ubo_size,
intr->src[0].ssa);
case nir_intrinsic_get_ssbo_size:
return load_sysval_indirect(b, 1, 32, stage_table(b), &s->ssbo_size,
intr->src[0].ssa);
case nir_intrinsic_load_vertex_param_buffer_poly:
return load_sysval_root(b, 1, 64, &u->vertex_params);
case nir_intrinsic_load_geometry_param_buffer_poly:
return load_sysval_root(b, 1, 64, &u->geometry_params);
case nir_intrinsic_load_vs_outputs_poly:
return load_sysval_root(b, 1, 64, &u->vertex_outputs);
case nir_intrinsic_load_tess_param_buffer_poly:
return load_sysval_root(b, 1, 64, &u->tess_params);
case nir_intrinsic_load_fixed_point_size_agx:
return load_sysval_root(b, 1, 32, &u->fixed_point_size);
case nir_intrinsic_load_tex_sprite_mask_agx:
return load_sysval_root(b, 1, 16, &u->sprite_mask);
case nir_intrinsic_load_shader_part_tests_zs_agx:
return load_sysval_root(b, 1, 16, &u->no_epilog_discard);
case nir_intrinsic_load_clip_z_coeff:
return nir_f2f32(b, load_sysval_root(b, 1, 16, &u->clip_z_coeff));
case nir_intrinsic_load_rasterization_stream:
return nir_imm_int(b, 0);
case nir_intrinsic_load_depth_never_agx:
/* TODO: Do we need this workaround for anything in GL? */
return nir_imm_intN_t(b, 0, 16);
case nir_intrinsic_load_uvs_index_agx:
return load_sysval_root(
b, 1, 16, &u->uvs_index[nir_intrinsic_io_semantics(intr).location]);
case nir_intrinsic_load_is_first_fan_agx:
return nir_ieq_imm(b, load_provoking_vtx(b), 1);
case nir_intrinsic_load_provoking_last:
return nir_b2b32(b, nir_ieq_imm(b, load_provoking_vtx(b), 2));
default:
break;
}
if (!lower_draw_params)
return NULL;
switch (intr->intrinsic) {
case nir_intrinsic_load_num_workgroups:
return load_sysval(b, 3, 32, AGX_SYSVAL_TABLE_GRID, 0);
case nir_intrinsic_load_first_vertex:
return load_sysval(b, 1, 32, AGX_SYSVAL_TABLE_PARAMS, 0);
case nir_intrinsic_load_base_instance:
return load_sysval(b, 1, 32, AGX_SYSVAL_TABLE_PARAMS, 4);
case nir_intrinsic_load_base_vertex:
/* first vertex if indexed, 0 otherwise. More efficient for our hw than
* the lowering in NIR.
*/
return nir_bcsel(
b, nir_i2b(b, load_sysval_root(b, 1, 16, &u->is_indexed_draw)),
load_sysval(b, 1, 32, AGX_SYSVAL_TABLE_PARAMS, 0), nir_imm_int(b, 0));
case nir_intrinsic_load_draw_id:
return load_sysval_root(b, 1, 32, &u->draw_id);
default:
return NULL;
}
}
/* Step 1. Lower NIR sysvals */
static bool
lower_sysvals(nir_builder *b, nir_instr *instr, void *data)
{
bool *lower_draw_params = data;
b->cursor = nir_before_instr(instr);
nir_def *old;
nir_def *replacement = NULL;
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
old = &intr->def;
replacement = lower_intrinsic(b, intr, *lower_draw_params);
} else if (instr->type == nir_instr_type_tex) {
nir_tex_instr *tex = nir_instr_as_tex(instr);
old = &tex->def;
if (tex->op != nir_texop_lod_bias)
return false;
struct agx_stage_uniforms *s = NULL;
int src_idx = nir_tex_instr_src_index(tex, nir_tex_src_texture_offset);
if (src_idx >= 0) {
replacement = load_sysval_indirect(
b, 1, 16, stage_table(b), s->lod_bias, tex->src[src_idx].src.ssa);
} else {
replacement = load_sysval(b, 1, 16, stage_table(b),
(uintptr_t)&s->lod_bias[tex->sampler_index]);
}
}
if (replacement != NULL) {
nir_def_rewrite_uses(old, replacement);
return true;
} else {
return false;
}
}
/* Step 2: Record system value loads */
static bool
record_loads(nir_builder *b, nir_intrinsic_instr *intr, void *data)
{
if (intr->intrinsic != nir_intrinsic_load_sysval_agx)
return false;
assert(intr->def.bit_size >= 16 && "no 8-bit sysvals");
unsigned dim = intr->def.num_components;
unsigned element_size = intr->def.bit_size / 16;
unsigned length = dim * element_size;
struct state *state = data;
struct table_state *table = &state->tables[nir_intrinsic_desc_set(intr)];
unsigned offset = nir_intrinsic_binding(intr);
assert((offset % 2) == 0 && "all entries are aligned by ABI");
BITSET_SET_COUNT(table->pushed, (offset / 2), length);
for (unsigned i = 0; i < length; ++i) {
if (table->element_size[(offset / 2) + i])
assert((table->element_size[(offset / 2) + i]) == element_size);
else
table->element_size[(offset / 2) + i] = element_size;
}
util_dynarray_append(&state->loads, intr);
return false;
}
/* Step 3: Decide where to push the system values */
static struct agx_push_range *
find_push_range_containing(struct agx_compiled_shader *shader, uint8_t table,
uint16_t offset)
{
for (unsigned i = 0; i < shader->push_range_count; ++i) {
struct agx_push_range *range = &shader->push[i];
if (range->table != table)
continue;
/* range->length is 16-bit words, need to convert. offset is bytes. */
uint16_t length_B = range->length * 2;
if (range->offset <= offset && offset < (range->offset + length_B))
return range;
}
UNREACHABLE("no containing range");
}
static unsigned
lay_out_table(struct agx_compiled_shader *shader, struct table_state *state,
unsigned table_index, unsigned uniform)
{
unsigned start, end;
BITSET_FOREACH_RANGE(start, end, state->pushed, sizeof(state->pushed) * 8) {
unsigned range_start = start;
do {
uint8_t size = state->element_size[range_start];
/* Find a range of constant element size. [range_start, range_end).
* Ranges may be at most 64 halfs.
*/
unsigned range_end;
for (range_end = range_start + 1;
range_end < end && state->element_size[range_end] == size &&
range_end < range_start + 64;
++range_end)
;
/* Now make the range with the given size (naturally aligned) */
uniform = ALIGN_POT(uniform, size);
assert((shader->push_range_count < ARRAY_SIZE(shader->push)) &&
"AGX_MAX_PUSH_RANGES must be an upper bound");
/* Offsets must be aligned to 4 bytes, this may require pushing a
* little more than intended (otherwise we would need extra copies)
*/
range_start = ROUND_DOWN_TO(range_start, 4 / 2);
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = uniform,
.table = table_index,
.offset = range_start * 2 /* bytes, not elements */,
.length = (range_end - range_start),
};
uniform += (range_end - range_start);
range_start = range_end;
} while (range_start < end);
}
return uniform;
}
static unsigned
lay_out_uniforms(struct agx_compiled_shader *shader, struct state *state)
{
unsigned uniform = 0;
if (state->stage == MESA_SHADER_VERTEX ||
state->stage == MESA_SHADER_TESS_EVAL) {
unsigned count =
DIV_ROUND_UP(BITSET_LAST_BIT(shader->attrib_components_read), 4);
struct agx_draw_uniforms *u = NULL;
if (count) {
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_VUNI_VBO_BASE(0),
.table = AGX_SYSVAL_TABLE_ROOT,
.offset = (uintptr_t)&u->attrib_base,
.length = 4 * count,
};
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_VUNI_VBO_CLAMP(count, 0),
.table = AGX_SYSVAL_TABLE_ROOT,
.offset = (uintptr_t)&u->attrib_clamp,
.length = 2 * count,
};
}
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_VUNI_FIRST_VERTEX(count),
.table = AGX_SYSVAL_TABLE_PARAMS,
.offset = 0,
.length = 4,
};
bool sw = state->hw_stage == MESA_SHADER_COMPUTE;
if (sw) {
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_VUNI_VERTEX_PARAMS(count),
.table = AGX_SYSVAL_TABLE_ROOT,
.offset = (uintptr_t)&u->vertex_params,
.length = 4,
};
}
uniform = AGX_ABI_VUNI_COUNT_GL(count, sw);
} else if (state->stage == MESA_SHADER_FRAGMENT) {
struct agx_draw_uniforms *u = NULL;
struct agx_stage_uniforms *s = NULL;
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_FUNI_EMRT_HEAP,
.table = AGX_SYSVAL_TABLE_FS,
.offset = (uintptr_t)&s->texture_base,
.length = 4,
};
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_FUNI_BLEND_R,
.table = AGX_SYSVAL_TABLE_ROOT,
.offset = (uintptr_t)&u->blend_constant,
.length = 8,
};
shader->push[shader->push_range_count++] = (struct agx_push_range){
.uniform = AGX_ABI_FUNI_ROOT,
.table = AGX_SYSVAL_TABLE_ROOT,
.offset = (uintptr_t)&u->tables[AGX_SYSVAL_TABLE_ROOT],
.length = 4,
};
uniform = AGX_ABI_FUNI_COUNT;
}
/* Lay out each system value table. We do this backwards to ensure the first
* uniform goes to the bindless texture base.
*/
for (int t = AGX_NUM_SYSVAL_TABLES - 1; t >= 0; --t)
uniform = lay_out_table(shader, &state->tables[t], t, uniform);
/* Step 4: Fill in the loads */
util_dynarray_foreach(&state->loads, nir_intrinsic_instr *, intr_) {
nir_intrinsic_instr *intr = *intr_;
uint8_t table = nir_intrinsic_desc_set(intr);
uint16_t offset = nir_intrinsic_binding(intr);
bool bindless_image = nir_intrinsic_flags(intr);
struct agx_push_range *range =
find_push_range_containing(shader, table, offset);
unsigned base = range->uniform + ((offset - range->offset) / 2);
nir_builder b = nir_builder_at(nir_before_instr(&intr->instr));
if (bindless_image) {
nir_instr *next = nir_instr_next(&intr->instr);
assert(next->type == nir_instr_type_intrinsic);
nir_intrinsic_instr *nintr = nir_instr_as_intrinsic(next);
assert(nintr->intrinsic == nir_intrinsic_bindless_image_agx);
nir_intrinsic_set_desc_set(nintr, base);
} else {
nir_def *repl = nir_load_preamble(&b, intr->def.num_components,
intr->def.bit_size, .base = base);
nir_def_replace(&intr->def, repl);
}
}
return uniform;
}
bool
agx_nir_lower_sysvals(nir_shader *shader, mesa_shader_stage desc_stage,
bool lower_draw_params)
{
/* override stage for the duration on the pass. XXX: should refactor, but
* it's annoying!
*/
mesa_shader_stage phys_stage = shader->info.stage;
shader->info.stage = desc_stage;
bool progress = nir_shader_instructions_pass(
shader, lower_sysvals, nir_metadata_control_flow, &lower_draw_params);
shader->info.stage = phys_stage;
return progress;
}
bool
agx_nir_layout_uniforms(nir_shader *shader,
struct agx_compiled_shader *compiled,
unsigned *push_size)
{
struct state state = {
.stage = compiled->stage,
.hw_stage = shader->info.stage,
};
nir_shader_intrinsics_pass(shader, record_loads, nir_metadata_control_flow,
&state);
*push_size = lay_out_uniforms(compiled, &state);
util_dynarray_fini(&state.loads);
/* Make sure texture handles have constants associated */
nir_opt_constant_folding(shader);
return true;
}
File diff suppressed because it is too large. Load diff
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright 2010 Red Hat Inc.
* SPDX-License-Identifier: MIT
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
struct pipe_screen;
struct renderonly;
struct pipe_screen *agx_screen_create(int fd, struct renderonly *ro,
const struct pipe_screen_config *config);
#ifdef __cplusplus
}
#endif
+641
View File
@@ -0,0 +1,641 @@
/*
* Copyright 2022 Alyssa Rosenzweig
* Copyright 2019-2020 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include "pipe/p_defines.h"
#include "util/bitset.h"
#include "util/macros.h"
#include "util/ralloc.h"
#include "util/u_dump.h"
#include "util/u_inlines.h"
#include "agx_abi.h"
#include "agx_bo.h"
#include "agx_device.h"
#include "agx_state.h"
#include "libagx.h"
#include "libagx_dgc.h"
#include "libagx_shaders.h"
static bool
is_occlusion(struct agx_query *query)
{
switch (query->type) {
case PIPE_QUERY_OCCLUSION_COUNTER:
case PIPE_QUERY_OCCLUSION_PREDICATE:
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
return true;
default:
return false;
}
}
static bool
is_timer(struct agx_query *query)
{
switch (query->type) {
case PIPE_QUERY_TIMESTAMP:
case PIPE_QUERY_TIME_ELAPSED:
return true;
default:
return false;
}
}
struct agx_oq_heap {
/* The GPU allocation itself */
struct agx_device *dev;
struct agx_bo *bo;
/* Bitset of query indices that are in use */
BITSET_DECLARE(available, AGX_MAX_OCCLUSION_QUERIES);
};
static void
agx_destroy_oq_heap(void *heap_)
{
struct agx_oq_heap *heap = heap_;
agx_bo_unreference(heap->dev, heap->bo);
}
static struct agx_oq_heap *
agx_alloc_oq_heap(struct agx_context *ctx)
{
struct agx_oq_heap *heap = rzalloc(ctx, struct agx_oq_heap);
ralloc_set_destructor(heap, agx_destroy_oq_heap);
heap->dev = agx_device(ctx->base.screen);
heap->bo =
agx_bo_create(heap->dev, AGX_MAX_OCCLUSION_QUERIES * sizeof(uint64_t), 0,
AGX_BO_WRITEBACK, "Occlusion query heap");
/* At the start, everything is available */
BITSET_ONES(heap->available);
return heap;
}
static struct agx_oq_heap *
agx_get_oq_heap(struct agx_context *ctx)
{
if (!ctx->oq)
ctx->oq = agx_alloc_oq_heap(ctx);
return ctx->oq;
}
static struct agx_ptr
agx_alloc_oq(struct agx_context *ctx)
{
struct agx_oq_heap *heap = agx_get_oq_heap(ctx);
/* Find first available */
int ffs = BITSET_FFS(heap->available);
if (!ffs)
return (struct agx_ptr){NULL, 0};
/* Allocate it */
unsigned index = ffs - 1;
BITSET_CLEAR(heap->available, index);
unsigned offset = index * sizeof(uint64_t);
return (struct agx_ptr){
(uint8_t *)agx_bo_map(heap->bo) + offset,
heap->bo->va->addr + offset,
};
}
static unsigned
agx_oq_index(struct agx_context *ctx, struct agx_query *q)
{
assert(is_occlusion(q));
return (q->ptr.gpu - ctx->oq->bo->va->addr) / sizeof(uint64_t);
}
static void
agx_free_oq(struct agx_context *ctx, struct agx_query *q)
{
struct agx_oq_heap *heap = agx_get_oq_heap(ctx);
unsigned index = agx_oq_index(ctx, q);
assert(index < AGX_MAX_OCCLUSION_QUERIES);
assert(!BITSET_TEST(heap->available, index));
BITSET_SET(heap->available, index);
}
uint64_t
agx_get_occlusion_heap(struct agx_batch *batch)
{
if (!batch->ctx->oq)
return 0;
struct agx_bo *bo = batch->ctx->oq->bo;
if (agx_batch_uses_bo(batch, bo))
return bo->va->addr;
else
return 0;
}
static struct pipe_query *
agx_create_query(struct pipe_context *ctx, unsigned query_type, unsigned index)
{
struct agx_query *query = calloc(1, sizeof(struct agx_query));
query->type = query_type;
query->index = index;
/* Set all writer generations to a sentinel that will always compare as
* false, since nothing writes to no queries.
*/
for (unsigned i = 0; i < ARRAY_SIZE(query->writer_generation); ++i) {
query->writer_generation[i] = UINT64_MAX;
}
if (is_occlusion(query)) {
query->ptr = agx_alloc_oq(agx_context(ctx));
} else {
/* TODO: a BO for the query is wasteful, but we benefit from BO list
* tracking / reference counting to deal with lifetimes.
*/
query->bo = agx_bo_create(agx_device(ctx->screen), sizeof(uint64_t) * 2,
0, AGX_BO_WRITEBACK, "Query");
query->ptr = (struct agx_ptr){
.gpu = query->bo->va->addr,
.cpu = agx_bo_map(query->bo),
};
}
if (!query->ptr.gpu) {
free(query);
return NULL;
}
return (struct pipe_query *)query;
}
static void
flush_query_writers(struct agx_context *ctx, struct agx_query *query,
const char *reason)
{
STATIC_ASSERT(ARRAY_SIZE(ctx->batches.generation) == AGX_MAX_BATCHES);
STATIC_ASSERT(ARRAY_SIZE(ctx->batches.slots) == AGX_MAX_BATCHES);
STATIC_ASSERT(ARRAY_SIZE(query->writer_generation) == AGX_MAX_BATCHES);
for (unsigned i = 0; i < AGX_MAX_BATCHES; ++i) {
if (query->writer_generation[i] == ctx->batches.generation[i])
agx_flush_batch_for_reason(ctx, &ctx->batches.slots[i], reason);
}
}
static void
sync_query_writers(struct agx_context *ctx, struct agx_query *query,
const char *reason)
{
for (unsigned i = 0; i < AGX_MAX_BATCHES; ++i) {
if (query->writer_generation[i] == ctx->batches.generation[i])
agx_sync_batch_for_reason(ctx, &ctx->batches.slots[i], reason);
}
}
static bool
is_query_busy(struct agx_context *ctx, struct agx_query *query)
{
for (unsigned i = 0; i < AGX_MAX_BATCHES; ++i) {
if (query->writer_generation[i] == ctx->batches.generation[i])
return true;
}
return false;
}
static void
agx_destroy_query(struct pipe_context *pctx, struct pipe_query *pquery)
{
struct agx_context *ctx = agx_context(pctx);
struct agx_query *query = (struct agx_query *)pquery;
struct agx_device *dev = agx_device(pctx->screen);
/* We don't reference count the occlusion query allocations, so we need to
* sync writers when destroying so we can freely write from the CPU after
* it's destroyed, since the driver will assume an available query is idle.
*
* For other queries, the BO itself is reference counted after the pipe_query
* is destroyed so we don't need to flush.
*/
if (is_occlusion(query)) {
sync_query_writers(ctx, query, "Occlusion query destroy");
agx_free_oq(ctx, query);
} else {
agx_bo_unreference(dev, query->bo);
}
free(pquery);
}
static bool
agx_begin_query(struct pipe_context *pctx, struct pipe_query *pquery)
{
struct agx_context *ctx = agx_context(pctx);
struct agx_query *query = (struct agx_query *)pquery;
ctx->dirty |= AGX_DIRTY_QUERY;
switch (query->type) {
case PIPE_QUERY_OCCLUSION_COUNTER:
case PIPE_QUERY_OCCLUSION_PREDICATE:
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
ctx->occlusion_query = query;
break;
case PIPE_QUERY_PRIMITIVES_GENERATED:
ctx->prims_generated[query->index] = query;
break;
case PIPE_QUERY_PRIMITIVES_EMITTED:
ctx->tf_prims_generated[query->index] = query;
break;
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
ctx->tf_overflow[query->index] = query;
break;
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
ctx->tf_any_overflow = query;
break;
case PIPE_QUERY_TIME_ELAPSED:
ctx->time_elapsed = query;
break;
case PIPE_QUERY_TIMESTAMP:
/* No-op */
break;
case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
assert(query->index < ARRAY_SIZE(ctx->pipeline_statistics));
ctx->pipeline_statistics[query->index] = query;
break;
default:
return false;
}
/* begin_query zeroes, sync so we can do that write from the CPU */
sync_query_writers(ctx, query, "Query overwritten");
uint64_t *ptr = query->ptr.cpu;
ptr[0] = 0;
if (query->type == PIPE_QUERY_TIME_ELAPSED) {
/* Timestamp begin in second record, the timestamp end in the first */
ptr[1] = UINT64_MAX;
}
return true;
}
static bool
agx_end_query(struct pipe_context *pctx, struct pipe_query *pquery)
{
struct agx_context *ctx = agx_context(pctx);
struct agx_device *dev = agx_device(pctx->screen);
struct agx_query *query = (struct agx_query *)pquery;
ctx->dirty |= AGX_DIRTY_QUERY;
switch (query->type) {
case PIPE_QUERY_OCCLUSION_COUNTER:
case PIPE_QUERY_OCCLUSION_PREDICATE:
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
ctx->occlusion_query = NULL;
return true;
case PIPE_QUERY_PRIMITIVES_GENERATED:
ctx->prims_generated[query->index] = NULL;
return true;
case PIPE_QUERY_PRIMITIVES_EMITTED:
ctx->tf_prims_generated[query->index] = NULL;
return true;
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
ctx->tf_overflow[query->index] = NULL;
return true;
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
ctx->tf_any_overflow = NULL;
return true;
case PIPE_QUERY_TIME_ELAPSED:
ctx->time_elapsed = NULL;
return true;
case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
assert(query->index < ARRAY_SIZE(ctx->pipeline_statistics));
ctx->pipeline_statistics[query->index] = NULL;
return true;
case PIPE_QUERY_TIMESTAMP: {
/* Timestamp logically written now, set up batches to MAX their finish
* time in. If there are no batches, it's just the current time stamp.
*/
agx_add_timestamp_end_query(ctx, query);
uint64_t *value = query->ptr.cpu;
*value = agx_get_gpu_timestamp(dev);
return true;
}
default:
return false;
}
}
enum query_copy_type {
QUERY_COPY_NORMAL,
QUERY_COPY_BOOL32,
QUERY_COPY_BOOL64,
QUERY_COPY_TIMESTAMP,
QUERY_COPY_TIME_ELAPSED,
};
static enum query_copy_type
classify_query_type(enum pipe_query_type type)
{
switch (type) {
case PIPE_QUERY_OCCLUSION_PREDICATE:
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
return QUERY_COPY_BOOL32;
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
return QUERY_COPY_BOOL64;
case PIPE_QUERY_TIMESTAMP:
return QUERY_COPY_TIMESTAMP;
case PIPE_QUERY_TIME_ELAPSED:
return QUERY_COPY_TIME_ELAPSED;
default:
return QUERY_COPY_NORMAL;
}
}
static bool
agx_get_query_result(struct pipe_context *pctx, struct pipe_query *pquery,
bool wait, union pipe_query_result *vresult)
{
struct agx_query *query = (struct agx_query *)pquery;
struct agx_context *ctx = agx_context(pctx);
struct agx_device *dev = agx_device(pctx->screen);
/* TODO: Honour `wait` */
sync_query_writers(ctx, query, "Reading query results");
uint64_t *ptr = query->ptr.cpu;
uint64_t value = *ptr;
switch (classify_query_type(query->type)) {
case QUERY_COPY_BOOL32:
vresult->u64 = ((uint32_t)value) != 0;
return true;
case QUERY_COPY_BOOL64:
vresult->u64 = value != 0;
return true;
case QUERY_COPY_NORMAL:
vresult->u64 = value;
return true;
case QUERY_COPY_TIMESTAMP:
vresult->u64 = agx_gpu_timestamp_to_ns(dev, value);
return true;
case QUERY_COPY_TIME_ELAPSED:
/* end - begin */
vresult->u64 = agx_gpu_timestamp_to_ns(dev, ptr[0] - ptr[1]);
return true;
default:
UNREACHABLE("Other queries not yet supported");
}
}
static unsigned
result_type_size(enum pipe_query_value_type result_type)
{
return (result_type <= PIPE_QUERY_TYPE_U32) ? 4 : 8;
}
static void
agx_get_query_result_resource_cpu(struct agx_context *ctx,
struct agx_query *query,
enum pipe_query_flags flags,
enum pipe_query_value_type result_type,
int index, struct pipe_resource *resource,
unsigned offset)
{
union pipe_query_result result;
if (index < 0) {
/* availability */
result.u64 = !is_query_busy(ctx, query);
} else {
bool ready =
agx_get_query_result(&ctx->base, (void *)query, true, &result);
assert(ready);
}
/* Clamp to type, arb_query_buffer_object-qbo tests */
if (result_type == PIPE_QUERY_TYPE_U32) {
result.u32 = MIN2(result.u64, u_uintN_max(32));
} else if (result_type == PIPE_QUERY_TYPE_I32) {
int64_t x = result.u64;
x = MAX2(MIN2(x, u_intN_max(32)), u_intN_min(32));
result.u32 = x;
}
pipe_buffer_write(&ctx->base, resource, offset,
result_type_size(result_type), &result.u64);
}
static bool
agx_get_query_result_resource_gpu(struct agx_context *ctx,
struct agx_query *query,
enum pipe_query_flags flags,
enum pipe_query_value_type result_type,
int index, struct pipe_resource *prsrc,
unsigned offset)
{
/* Handle availability queries on CPU */
if (index < 0)
return false;
/* TODO: timer queries on GPU */
if (query->type == PIPE_QUERY_TIMESTAMP ||
query->type == PIPE_QUERY_TIME_ELAPSED)
return false;
flush_query_writers(ctx, query, util_str_query_type(query->type, true));
struct agx_resource *rsrc = agx_resource(prsrc);
enum query_copy_type copy_type = classify_query_type(query->type);
struct agx_batch *batch = agx_get_compute_batch(ctx);
agx_batch_init_state(batch);
agx_dirty_all(ctx);
/* Set params */
agx_batch_writes_range(batch, rsrc, offset, result_type_size(result_type));
unsigned bool_size = copy_type == QUERY_COPY_BOOL64 ? 8
: copy_type == QUERY_COPY_BOOL32 ? 4
: 0;
libagx_copy_query_gl(batch, agx_1d(1), AGX_BARRIER_ALL, query->ptr.gpu,
agx_map_gpu(rsrc) + offset, result_type, bool_size);
return true;
}
static void
agx_get_query_result_resource(struct pipe_context *pipe, struct pipe_query *q,
enum pipe_query_flags flags,
enum pipe_query_value_type result_type, int index,
struct pipe_resource *resource, unsigned offset)
{
struct agx_query *query = (struct agx_query *)q;
struct agx_context *ctx = agx_context(pipe);
/* Try to copy on the GPU */
if (!agx_get_query_result_resource_gpu(ctx, query, flags, result_type, index,
resource, offset)) {
/* Else, fallback to CPU */
agx_get_query_result_resource_cpu(ctx, query, flags, result_type, index,
resource, offset);
}
}
static void
agx_set_active_query_state(struct pipe_context *pipe, bool enable)
{
struct agx_context *ctx = agx_context(pipe);
ctx->active_queries = enable;
ctx->dirty |= AGX_DIRTY_QUERY;
}
static void
agx_add_query_to_batch(struct agx_batch *batch, struct agx_query *query)
{
unsigned idx = agx_batch_idx(batch);
struct agx_bo *bo = is_occlusion(query) ? batch->ctx->oq->bo : query->bo;
agx_batch_add_bo(batch, bo);
query->writer_generation[idx] = batch->ctx->batches.generation[idx];
}
void
agx_batch_add_timestamp_query(struct agx_batch *batch, struct agx_query *q)
{
if (q) {
agx_add_query_to_batch(batch, q);
util_dynarray_append(&batch->timestamps, q->ptr);
}
}
uint16_t
agx_get_oq_index(struct agx_batch *batch, struct agx_query *query)
{
agx_add_query_to_batch(batch, query);
return agx_oq_index(batch->ctx, query);
}
uint64_t
agx_get_query_address(struct agx_batch *batch, struct agx_query *query)
{
if (query) {
agx_add_query_to_batch(batch, query);
return query->ptr.gpu;
} else {
return AGX_SCRATCH_PAGE_ADDRESS;
}
}
void
agx_finish_batch_queries(struct agx_batch *batch, uint64_t begin_ts,
uint64_t end_ts)
{
/* Remove the batch as write from all queries by incrementing the generation
* of the batch.
*/
batch->ctx->batches.generation[agx_batch_idx(batch)]++;
/* Write out timestamps */
util_dynarray_foreach(&batch->timestamps, struct agx_ptr, it) {
uint64_t *ptr = it->cpu;
ptr[0] = MAX2(ptr[0], end_ts);
ptr[1] = MIN2(ptr[1], begin_ts);
}
}
void
agx_query_increment_cpu(struct agx_context *ctx, struct agx_query *query,
uint64_t increment)
{
if (!query)
return;
sync_query_writers(ctx, query, "CPU query increment");
uint64_t *value = query->ptr.cpu;
*value += increment;
}
static void
agx_render_condition(struct pipe_context *pipe, struct pipe_query *query,
bool condition, enum pipe_render_cond_flag mode)
{
struct agx_context *ctx = agx_context(pipe);
ctx->cond_query = query;
ctx->cond_cond = condition;
ctx->cond_mode = mode;
}
bool
agx_render_condition_check_inner(struct agx_context *ctx)
{
assert(ctx->cond_query != NULL && "precondition");
perf_debug_ctx(ctx, "Implementing conditional rendering on the CPU");
union pipe_query_result res = {0};
bool wait = ctx->cond_mode != PIPE_RENDER_COND_NO_WAIT &&
ctx->cond_mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT;
struct pipe_query *pq = (struct pipe_query *)ctx->cond_query;
if (agx_get_query_result(&ctx->base, pq, wait, &res))
return res.u64 != ctx->cond_cond;
return true;
}
void
agx_init_query_functions(struct pipe_context *pctx)
{
pctx->create_query = agx_create_query;
pctx->destroy_query = agx_destroy_query;
pctx->begin_query = agx_begin_query;
pctx->end_query = agx_end_query;
pctx->get_query_result = agx_get_query_result;
pctx->get_query_result_resource = agx_get_query_result_resource;
pctx->set_active_query_state = agx_set_active_query_state;
pctx->render_condition = agx_render_condition;
/* By default queries are active */
agx_context(pctx)->active_queries = true;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+183
View File
@@ -0,0 +1,183 @@
/*
* Copyright 2023 Alyssa Rosenzweig
* Copyright 2022 Collabora Ltd.
* SPDX-License-Identifier: MIT
*/
#include "compiler/nir/nir_builder.h"
#include "compiler/nir/nir_xfb_info.h"
#include "pipe/p_defines.h"
#include "util/u_draw.h"
#include "util/u_dump.h"
#include "util/u_inlines.h"
#include "util/u_prim.h"
#include "agx_state.h"
static struct pipe_stream_output_target *
agx_create_stream_output_target(struct pipe_context *pctx,
struct pipe_resource *prsc,
unsigned buffer_offset, unsigned buffer_size)
{
struct agx_streamout_target *target =
rzalloc(pctx, struct agx_streamout_target);
if (!target)
return NULL;
pipe_reference_init(&target->base.reference, 1);
pipe_resource_reference(&target->base.buffer, prsc);
target->base.context = pctx;
target->base.buffer_offset = buffer_offset;
target->base.buffer_size = buffer_size;
uint32_t zero = 0;
target->offset = pipe_buffer_create_with_data(pctx, PIPE_BIND_GLOBAL,
PIPE_USAGE_DEFAULT, 4, &zero);
return &target->base;
}
static void
agx_stream_output_target_destroy(struct pipe_context *pctx,
struct pipe_stream_output_target *target)
{
struct agx_streamout_target *tgt = agx_so_target(target);
pipe_resource_reference(&tgt->base.buffer, NULL);
pipe_resource_reference(&tgt->offset, NULL);
ralloc_free(target);
}
static void
agx_set_stream_output_targets(struct pipe_context *pctx, unsigned num_targets,
struct pipe_stream_output_target **targets,
const unsigned *offsets,
enum mesa_prim output_prim)
{
struct agx_context *ctx = agx_context(pctx);
struct agx_streamout *so = &ctx->streamout;
assert(num_targets <= ARRAY_SIZE(so->targets));
for (unsigned i = 0; i < num_targets; i++) {
/* From the Gallium documentation:
*
* -1 means the buffer should be appended to, and everything else sets
* the internal offset.
*
* We append regardless, so just check for != -1. Yes, using a negative
* sentinel value with an unsigned type is bananas. But it's in the
* Gallium contract and it will work out fine. Probably should be
* redefined to be ~0 instead of -1 but it doesn't really matter.
*/
if (offsets[i] != -1 && targets[i] != NULL) {
pipe_buffer_write(pctx, agx_so_target(targets[i])->offset, 0, 4,
&offsets[i]);
}
pipe_so_target_reference(&so->targets[i], targets[i]);
}
for (unsigned i = num_targets; i < so->num_targets; i++)
pipe_so_target_reference(&so->targets[i], NULL);
so->num_targets = num_targets;
}
static struct pipe_stream_output_target *
get_target(struct agx_context *ctx, unsigned buffer)
{
if (buffer < ctx->streamout.num_targets)
return ctx->streamout.targets[buffer];
else
return NULL;
}
/*
* Return the address of the indexed streamout buffer. This will be
* pushed into the streamout shader.
*/
uint64_t
agx_batch_get_so_address(struct agx_batch *batch, unsigned buffer,
uint32_t *size)
{
struct pipe_stream_output_target *target = get_target(batch->ctx, buffer);
/* If there's no target, don't write anything */
if (!target) {
*size = 0;
return 0;
}
/* Otherwise, write the target */
struct agx_resource *rsrc = agx_resource(target->buffer);
agx_batch_writes_range(batch, rsrc, target->buffer_offset,
target->buffer_size);
*size = target->buffer_size;
return agx_map_gpu(rsrc) + target->buffer_offset;
}
void
agx_draw_vbo_from_xfb(struct pipe_context *pctx,
const struct pipe_draw_info *info, unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect)
{
perf_debug_ctx(agx_context(pctx), "draw auto");
struct agx_streamout_target *so =
agx_so_target(indirect->count_from_stream_output);
unsigned offset_B = 0;
pipe_buffer_read(pctx, so->offset, 0, 4, &offset_B);
unsigned count = offset_B / so->stride;
struct pipe_draw_start_count_bias draw = {
.start = 0,
.count = count,
};
pctx->draw_vbo(pctx, info, drawid_offset, NULL, &draw, 1);
}
static uint32_t
xfb_prims_for_vertices(enum mesa_prim mode, unsigned verts)
{
uint32_t prims = u_decomposed_prims_for_vertices(mode, verts);
/* The GL spec isn't super clear about this, but it implies that quads are
* supposed to be tessellated into primitives and piglit
* (ext_transform_feedback-tessellation quads) checks this.
*/
if (u_decomposed_prim(mode) == MESA_PRIM_QUADS)
prims *= 2;
return prims;
}
/*
* Count generated primitives on the CPU for transform feedback. This only works
* in the absence of indirect draws, geometry shaders, or tessellation.
*/
void
agx_primitives_update_direct(struct agx_context *ctx,
const struct pipe_draw_info *info,
const struct pipe_draw_start_count_bias *draw)
{
assert(ctx->active_queries && ctx->prims_generated[0] && "precondition");
assert(!ctx->stage[MESA_SHADER_GEOMETRY].shader &&
"Geometry shaders use their own counting");
agx_query_increment_cpu(ctx, ctx->prims_generated[0],
xfb_prims_for_vertices(info->mode, draw->count));
}
void
agx_init_streamout_functions(struct pipe_context *ctx)
{
ctx->create_stream_output_target = agx_create_stream_output_target;
ctx->stream_output_target_destroy = agx_stream_output_target_destroy;
ctx->set_stream_output_targets = agx_set_stream_output_targets;
}
+152
View File
@@ -0,0 +1,152 @@
/*
* Copyright 2021 Alyssa Rosenzweig
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include "pipe/p_state.h"
#include "util/half_float.h"
#include "util/macros.h"
#include "agx_device.h"
#include "agx_state.h"
#include "pool.h"
static uint64_t
agx_const_buffer_ptr(struct agx_batch *batch, struct pipe_constant_buffer *cb)
{
if (cb->buffer) {
struct agx_resource *rsrc = agx_resource(cb->buffer);
agx_batch_reads(batch, rsrc);
return agx_map_gpu(rsrc) + cb->buffer_offset;
} else {
return 0;
}
}
void
agx_upload_vbos(struct agx_batch *batch)
{
struct agx_context *ctx = batch->ctx;
struct agx_vertex_elements *attribs = ctx->attributes;
uint64_t buffers[PIPE_MAX_ATTRIBS] = {0};
size_t buf_sizes[PIPE_MAX_ATTRIBS] = {0};
u_foreach_bit(vbo, ctx->vb_mask) {
struct pipe_vertex_buffer vb = ctx->vertex_buffers[vbo];
assert(!vb.is_user_buffer);
if (vb.buffer.resource) {
struct agx_resource *rsrc = agx_resource(vb.buffer.resource);
agx_batch_reads(batch, rsrc);
buffers[vbo] = agx_map_gpu(rsrc) + vb.buffer_offset;
buf_sizes[vbo] = rsrc->layout.size_B - vb.buffer_offset -
rsrc->layout.level_offsets_B[0];
}
}
for (unsigned i = 0; i < PIPE_MAX_ATTRIBS; ++i) {
unsigned buf = attribs->buffers[i];
uint64_t addr;
batch->uniforms.attrib_clamp[i] = agx_calculate_vbo_clamp(
buffers[buf], attribs->key[i].format, buf_sizes[buf],
attribs->key[i].stride, attribs->src_offsets[i], &addr);
batch->uniforms.attrib_base[i] = addr;
}
}
void
agx_upload_uniforms(struct agx_batch *batch)
{
struct agx_context *ctx = batch->ctx;
struct agx_ptr root_ptr = agx_pool_alloc_aligned(
&batch->pool, sizeof(struct agx_draw_uniforms), 16);
batch->uniforms.tables[AGX_SYSVAL_TABLE_ROOT] = root_ptr.gpu;
batch->uniforms.sample_mask = ctx->sample_mask;
assert(_mesa_float_to_half(0.5) == 0x3800);
batch->uniforms.clip_z_coeff =
(ctx->rast && !ctx->rast->base.clip_halfz) ? 0x3800 : 0x0;
batch->uniforms.sprite_mask =
(batch->reduced_prim == MESA_PRIM_POINTS && ctx->rast)
? ctx->rast->base.sprite_coord_enable
: 0;
memcpy(root_ptr.cpu, &batch->uniforms, sizeof(batch->uniforms));
}
void
agx_set_sampler_uniforms(struct agx_batch *batch, mesa_shader_stage stage)
{
struct agx_context *ctx = batch->ctx;
struct agx_stage *st = &ctx->stage[stage];
struct agx_stage_uniforms *unif = &batch->stage_uniforms[stage];
struct agx_device *dev = agx_device(ctx->base.screen);
u_foreach_bit(s, st->valid_samplers) {
unif->lod_bias[s] = st->samplers[s]->lod_bias_as_fp16;
}
/* If we use bindless samplers, insert sampler into the heap */
if (st->shader && st->shader->uses_bindless_samplers) {
u_foreach_bit(s, st->valid_samplers) {
unif->sampler_handle[s] =
28 +
agx_sampler_heap_add(dev, &batch->sampler_heap,
&st->samplers[s]->desc_without_custom_border);
}
}
}
void
agx_set_cbuf_uniforms(struct agx_batch *batch, mesa_shader_stage stage)
{
struct agx_stage *st = &batch->ctx->stage[stage];
struct agx_stage_uniforms *unif = &batch->stage_uniforms[stage];
u_foreach_bit(cb, st->cb_mask) {
unif->ubo_base[cb] = agx_const_buffer_ptr(batch, &st->cb[cb]);
unif->ubo_size[cb] = st->cb[cb].buffer_size;
}
}
void
agx_set_ssbo_uniforms(struct agx_batch *batch, mesa_shader_stage stage)
{
struct agx_stage *st = &batch->ctx->stage[stage];
struct agx_stage_uniforms *unif = &batch->stage_uniforms[stage];
/* Single element sink. TODO: Optimize with soft fault. */
uint32_t zeroes[4] = {0};
uint64_t sink = agx_pool_upload_aligned(&batch->pool, &zeroes, 16, 16);
/* Consider all shader buffers, needed to avoid faults with
* e.g. arb_shader_storage_buffer_object-array-ssbo-binding.
*/
for (unsigned cb = 0; cb < PIPE_MAX_SHADER_BUFFERS; ++cb) {
struct pipe_shader_buffer *sb = &st->ssbo[cb];
if (sb->buffer && st->ssbo[cb].buffer_size) {
struct agx_resource *rsrc = agx_resource(sb->buffer);
if (st->ssbo_writable_mask & BITFIELD_BIT(cb)) {
agx_batch_writes_range(batch, rsrc, sb->buffer_offset,
sb->buffer_size);
batch->incoherent_writes = true;
} else {
agx_batch_reads(batch, rsrc);
}
unif->ssbo_base[cb] = agx_map_gpu(rsrc) + sb->buffer_offset;
unif->ssbo_size[cb] = st->ssbo[cb].buffer_size;
} else {
/* Invalid, so use the sink */
unif->ssbo_base[cb] = sink;
unif->ssbo_size[cb] = 0;
}
}
}
@@ -0,0 +1,7 @@
/* asahi specific driconf options */
/* clang-format off */
DRI_CONF_SECTION_MISCELLANEOUS
DRI_CONF_HEAP_MEMORY_PERCENT(1.0f)
DRI_CONF_ASAHI_NO_FP16(false)
DRI_CONF_SECTION_END
+32
View File
@@ -0,0 +1,32 @@
# Copyright 2017 Intel Corporation
# SPDX-License-Identifier: MIT
files_asahi = files(
'driinfo_asahi.h',
'agx_batch.c',
'agx_blit.c',
'agx_disk_cache.c',
'agx_fence.c',
'agx_pipe.c',
'agx_nir_lower_sysvals.c',
'agx_nir_lower_bindings.c',
'agx_nir_lower_point_size.c',
'agx_query.c',
'agx_state.c',
'agx_streamout.c',
'agx_uniforms.c',
)
libasahi = static_library(
'asahi',
[files_asahi],
include_directories : [inc_gallium_aux, inc_gallium, inc_include, inc_src, inc_asahi, inc_virtio_gpu, inc_virtio_vdrm],
c_args : [c_msvc_compat_args, '-Wno-c2x-extensions'],
gnu_symbol_visibility : 'hidden',
dependencies : [idep_nir, idep_mesautil, idep_agx_pack, dep_libdrm, idep_libagx, idep_libagx_shaders_h],
)
driver_asahi = declare_dependency(
compile_args : '-DGALLIUM_ASAHI',
link_with : [libasahi, libasahiwinsys, libasahi_compiler, libasahi_lib, libasahi_layout, libasahi_decode]
)
@@ -0,0 +1,257 @@
KHR-GLES2.core.internalformat.texture2d.depth_component_unsigned_int_depth_component16,Fail
KHR-GLES2.core.internalformat.texture2d.depth_component_unsigned_int_depth_component24,Fail
KHR-GLES2.core.internalformat.texture2d.depth_component_unsigned_short_depth_component16,Fail
KHR-GLES2.core.internalformat.texture2d.rgb_float_rgb32f,Fail
KHR-GLES2.core.internalformat.texture2d.rgb_float_rgb32f_linear,Fail
KHR-GLES2.core.internalformat.texture2d.rgba_float_rgba32f,Fail
KHR-GLES2.core.internalformat.texture2d.rgba_float_rgba32f_linear,Fail
# Missing the red triangle
dEQP-GLES2.functional.clip_control.depth_mode_zero_to_one,Fail
# Clipped wide primitives not rendered when the ceneter is offscreen
dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_center,Fail
dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_corner,Fail
dEQP-GLES2.functional.clipping.point.wide_point_clip,Fail
dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_center,Fail
dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_corner,Fail
# Bad slope of clipped triangles
dEQP-GLES2.functional.clipping.triangle_vertex.clip_two.clip_neg_x_pos_z_and_neg_x_neg_y_neg_z,Fail
dEQP-GLES2.functional.clipping.triangle_vertex.clip_two.clip_neg_y_neg_z_and_neg_x_neg_y_pos_z,Fail
# RGB/RGBA half float should be incomplete, tested as complete.
dEQP-GLES2.functional.fbo.completeness.renderable.texture.color0.rgb_half_float_oes,Fail
dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod,Fail
# Subpixel precision errors
dEQP-GLES2.functional.texture.filtering.2d.linear_nearest_clamp_l8_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.linear_nearest_clamp_rgb888_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.linear_nearest_clamp_rgba4444_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.linear_nearest_clamp_rgba8888_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.nearest_linear_clamp_l8_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.nearest_linear_clamp_rgb888_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.nearest_linear_clamp_rgba4444_npot,Fail
dEQP-GLES2.functional.texture.filtering.2d.nearest_linear_clamp_rgba8888_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.linear_nearest_clamp_l8_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.linear_nearest_clamp_rgb888_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.linear_nearest_clamp_rgba4444_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.linear_nearest_clamp_rgba8888_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.nearest_linear_clamp_l8_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.nearest_linear_clamp_rgb888_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.nearest_linear_clamp_rgba4444_npot,Fail
dEQP-GLES2.functional.texture.filtering.cube.nearest_linear_clamp_rgba8888_npot,Fail
dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear,Fail
dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest,Fail
dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear,Fail
dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_nearest,Fail
dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_linear,Fail
dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_nearest,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_clamp,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_linear_mirror,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_clamp,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.linear_mipmap_linear_nearest_mirror,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.nearest_mipmap_linear_linear_clamp,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.nearest_mipmap_linear_linear_mirror,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.nearest_mipmap_linear_linear_repeat,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.nearest_mipmap_nearest_linear_clamp,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.nearest_mipmap_nearest_linear_mirror,Fail
dEQP-GLES2.functional.texture.vertex.cube.filtering.nearest_mipmap_nearest_linear_repeat,Fail
dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_clamp,Fail
dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_mirror,Fail
dEQP-GLES2.functional.texture.vertex.cube.wrap.clamp_repeat,Fail
dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_clamp,Fail
dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_mirror,Fail
dEQP-GLES2.functional.texture.vertex.cube.wrap.mirror_repeat,Fail
# No info, just piglit fail result.
shaders@glsl-bug-110796,Fail
# "glsl-routing: ../src/intel/compiler/brw_fs_visitor.cpp:155: fs_reg fs_visitor::interp_reg(int, int): Assertion `prog_data->urb_setup[location] >= 0' failed."
shaders@glsl-routing,Crash
# frontbuffer reading failures?
spec@!opengl [email protected],Fail
spec@!opengl 1.1@line-aa-width,Fail
spec@!opengl 1.1@linestipple,Fail
spec@!opengl 1.1@linestipple@Factor 2x,Fail
spec@!opengl 1.1@linestipple@Factor 3x,Fail
spec@!opengl 1.1@linestipple@Line loop,Fail
spec@!opengl 1.1@linestipple@Line strip,Fail
# abort()s submitting batchbuffer on context close, after some GL_OOMs.
spec@!opengl 1.1@max-texture-size,Crash
spec@!opengl [email protected],Fail
# Regression from i965
# "data not copied"
spec@arb_copy_buffer@targets,Fail
# "../src/mesa/state_tracker/st_cb_copyimage.c:309:swizzled_copy: Assertion `src_desc->block.bits == dst_desc->block.bits' failed."
spec@arb_copy_image@arb_copy_image-formats,Crash
# Regression from i965
spec@arb_depth_buffer_float@fbo-generatemipmap-formats,Fail
spec@arb_depth_buffer_float@fbo-generatemipmap-formats@GL_DEPTH_COMPONENT32F,Fail
spec@arb_depth_buffer_float@fbo-generatemipmap-formats@GL_DEPTH_COMPONENT32F NPOT,Fail
spec@arb_depth_buffer_float@texwrap formats bordercolor,Fail
spec@arb_depth_buffer_float@texwrap formats bordercolor-swizzled,Fail
spec@arb_depth_buffer_float@texwrap formats bordercolor-swizzled@GL_DEPTH32F_STENCIL8- swizzled- border color only,Fail
spec@arb_depth_buffer_float@texwrap formats bordercolor-swizzled@GL_DEPTH_COMPONENT32F- swizzled- border color only,Fail
spec@arb_depth_buffer_float@texwrap formats bordercolor@GL_DEPTH32F_STENCIL8- border color only,Fail
spec@arb_depth_buffer_float@texwrap formats bordercolor@GL_DEPTH_COMPONENT32F- border color only,Fail
# test bug: "Failed to compile fragment shader: 0:1(10): error: GLSL 1.30 is not supported. Supported versions are: 1.10, 1.20, and 1.00 ES"
spec@arb_framebuffer_object@fbo-drawbuffers-none use_frag_out,Fail
# "Left: textureCube, Right: textureCubeGradARB
# Probe color at (80,78)
# Left: 0.678431 0.333333 0.000000 1.000000
# Right: 0.647059 0.349020 0.000000 1.000000"
spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgradcube,Fail
# Regression from i965
spec@arb_texture_cube_map@copyteximage cube,Fail
# Regressions from i965: i965 would demote these 32-bit internalformats to
# 16-bit so that texture filtering worked, since GL 2.1 let you do that.
# Crocus instead decided to follow r300 and other GL2 hardware in using the
# requested size for storage even if the HW can't filter textures with it.
spec@arb_texture_rg@fbo-blending-formats-float,Fail
spec@arb_texture_rg@fbo-blending-formats-float@GL_RG32F,Fail
spec@arb_texture_float@texwrap formats bordercolor,Fail
spec@arb_texture_float@texwrap formats bordercolor-swizzled,Fail
spec@arb_texture_float@texwrap formats bordercolor-swizzled@GL_INTENSITY32F_ARB- swizzled- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor-swizzled@GL_LUMINANCE32F_ARB- swizzled- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor-swizzled@GL_LUMINANCE_ALPHA32F_ARB- swizzled- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor-swizzled@GL_RGB32F- swizzled- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor-swizzled@GL_RGBA32F- swizzled- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor@GL_INTENSITY32F_ARB- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor@GL_LUMINANCE32F_ARB- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor@GL_LUMINANCE_ALPHA32F_ARB- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor@GL_RGB32F- border color only,Fail
spec@arb_texture_float@texwrap formats bordercolor@GL_RGBA32F- border color only,Fail
spec@arb_texture_rg@texwrap formats-float bordercolor,Fail
spec@arb_texture_rg@texwrap formats-float bordercolor-swizzled,Fail
spec@arb_texture_rg@texwrap formats-float bordercolor-swizzled@GL_R32F- swizzled- border color only,Fail
spec@arb_texture_rg@texwrap formats-float bordercolor-swizzled@GL_RG32F- swizzled- border color only,Fail
spec@arb_texture_rg@texwrap formats-float bordercolor@GL_R32F- border color only,Fail
spec@arb_texture_rg@texwrap formats-float bordercolor@GL_RG32F- border color only,Fail
# test bug: "ERROR - Duplicate subtest found, marking test failed: cube array texture"
spec@arb_texture_storage@texture-storage@cube array texture,Fail
# Regression from i965
spec@arb_vertex_buffer_object@vbo-subdata-many drawarrays,Fail
spec@arb_vertex_buffer_object@vbo-subdata-many drawelements,Fail
spec@egl 1.4@eglterminate then unbind context,Fail
spec@egl_ext_protected_content@conformance,Fail
# "piglit: error: failed to get EGLConfig: EGL_NOT_INITIALIZED(0x3001)"
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_rgba,Fail
# "eglInitialize() failed"
spec@egl_khr_surfaceless_context@viewport,Fail
# Regression from i965
spec@ext_draw_buffers2@fbo-drawbuffers2-blend,Fail
# "Failed blit src(0,0;1,1) - dst(0,0;2147483647,2147483647)
# Failed blit src(0,0;40,40) - dst(0,0;134217727,134217727)
# Failed blit src(0,0;40,40) - dst(0,0;2147483647,2147483647)
# Failed blit src(0,0;80,80) - dst(0,0;134217727,134217727)
# Failed blit src(0,0;80,80) - dst(0,0;2147483647,2147483647)
# Failed blit src(0,0;160,160) - dst(0,0;134217727,134217727)
# Failed blit src(0,0;160,160) - dst(0,0;2147483647,2147483647)
# Failed blit src(0,0;2147483647,2147483647) - dst(0,0;2147483647,2147483647)"
spec@ext_framebuffer_blit@fbo-blit-check-limits,Fail
# "../src/mesa/state_tracker/st_atom_blend.c:156:blend_per_rt: Assertion `st->has_indep_blend_func' failed."
spec@ext_framebuffer_object@fbo-blending-format-quirks,Crash
# "piglit: error: Failed at level 1, slice 1"
spec@ext_gpu_shader4@execution@texelfetch@fs-texelfetch-isampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetch@fs-texelfetch-sampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetch@fs-texelfetch-usampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetch@vs-texelfetch-isampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetch@vs-texelfetch-sampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetch@vs-texelfetch-usampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetchoffset@fs-texelfetch-isampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetchoffset@fs-texelfetch-sampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetchoffset@fs-texelfetch-usampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetchoffset@vs-texelfetch-isampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetchoffset@vs-texelfetch-sampler3d,Fail
spec@ext_gpu_shader4@execution@texelfetchoffset@vs-texelfetch-usampler3d,Fail
# "Stopping after 100 failures
# Summary: -1/100 passed"
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture() 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture() 2darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture() cubeshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture(bias) 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture(bias) 2darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture(bias) cubeshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegrad 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegrad 2darray,Crash
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegrad 2darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegrad cubeshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegradoffset 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegradoffset 2darray,Crash
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturegradoffset 2darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturelod 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texturelodoffset 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4textureoffset 1darrayshadow,Fail
spec@ext_gpu_shader4@tex-miplevel-selection gpu4textureoffset 2darrayshadow,Fail
# Regression from i965
# "Testing GL_LUMINANCE16F_ARB
# Expected: (1, 1, 1, 0)
# Actual: (1, 1, 1, 1)"
spec@ext_packed_float@query-rgba-signed-components,Fail
# "Unexpected GL error: GL_NO_ERROR 0x0
# (Error at /home/anholt/src/piglit/tests/spec/ext_texture_format_bgra8888/api-errors.c:63)
# Expected GL error: GL_INVALID_OPERATION 0x502
# Unexpected GL error: GL_NO_ERROR 0x0
# (Error at /home/anholt/src/piglit/tests/spec/ext_texture_format_bgra8888/api-errors.c:69)
# Expected GL error: GL_INVALID_OPERATION 0x502
# Unexpected GL error: GL_NO_ERROR 0x0
# (Error at /home/anholt/src/piglit/tests/spec/ext_texture_format_bgra8888/api-errors.c:103)
# Expected GL error: GL_INVALID_OPERATION 0x502"
spec@ext_texture_format_bgra8888@api-errors,Fail
# no info, just fails
spec@intel_performance_query@intel_performance_query-issue_2235,Fail
# "Unexpected GL error: GL_INVALID_ENUM 0x500
# (Error at tests/spec/khr_texture_compression_astc/khr_compressed_astc-basic.c:349)
# Expected GL error: GL_INVALID_OPERATION 0x502"
spec@khr_texture_compression_astc@basic-gles,Fail
spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail
spec@khr_texture_compression_astc@miptree-gl srgb-fp@sRGB decode full precision,Fail
spec@khr_texture_compression_astc@miptree-gles srgb,Fail
spec@khr_texture_compression_astc@miptree-gles srgb-fp,Fail
# new failures, needs debugging
dEQP-GLES2.functional.polygon_offset.default_displacement_with_units,Fail
dEQP-GLES2.functional.polygon_offset.default_render_with_factor,Fail
dEQP-GLES2.functional.polygon_offset.fixed16_displacement_with_units,Fail
dEQP-GLES2.functional.polygon_offset.fixed16_render_with_factor,Fail
spec@!opengl 1.1@polygon-mode-offset,Fail
spec@!opengl 1.1@polygon-mode-offset@config 0: Expected white pixel on bottom edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 0: Expected white pixel on left edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 0: Expected white pixel on right edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 0: Expected white pixel on top edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 3: Expected white pixel on bottom edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 3: Expected white pixel on left edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 3: Expected white pixel on right edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 3: Expected white pixel on top edge,Fail
spec@amd_performance_monitor@measure,Crash
@@ -0,0 +1,35 @@
# These seem stable on their own (or when running their whole test group),
# but intermittently fail when mixed in with other tests.
dEQP-GLES2.functional.shaders.functions.control_flow.return_after_loop_sequence_fragment
dEQP-GLES2.functional.shaders.loops.do_while_uniform_iterations.nested_sequence_fragment
dEQP-GLES2.functional.shaders.loops.while_uniform_iterations.nested_tricky_dataflow_2_fragment
dEQP-GLES2.functional.shaders.loops.for_dynamic_iterations.nested_tricky_dataflow_2_fragment
dEQP-GLES2.functional.shaders.loops.for_dynamic_iterations.nested_sequence_fragment
dEQP-GLES2.functional.shaders.loops.for_uniform_iterations.basic_mediump_int_fragment
dEQP-GLES2.functional.shaders.loops.for_uniform_iterations.nested_sequence_fragment
KHR-GLES2.texture_3d.filtering.formats.rgba8_linear
KHR-GLES2.texture_3d.filtering.formats.rgba8_linear_mipmap_linear
KHR-GLES2.texture_3d.filtering.formats.rgba8_linear_mipmap_nearest
KHR-GLES2.texture_3d.filtering.formats.rgba8_nearest
spec@!opengl 2.0@attribs
spec@arb_map_buffer_range@copybuffersubdata decrement-offset
spec@arb_map_buffer_range@copybuffersubdata increment-offset
spec@arb_map_buffer_range@copybuffersubdata offset=0
spec@arb_texture_cube_map@copyteximage cube
spec@arb_vertex_buffer_object@vbo-subdata-many drawarrays
spec@arb_vertex_buffer_object@vbo-subdata-many drawelements
spec@arb_vertex_buffer_object@vbo-subdata-many drawrangeelements
spec@arb_vertex_type_2_10_10_10_rev@attribs
spec@ext_framebuffer_multisample@accuracy all_samples depth_resolve small depthstencil
spec@ext_gpu_shader4@tex-miplevel-selection gpu4texture() 2darray
# GL_MAX_VARYING_FLOATS = 64
# Probe color at (2,2)
# Expected: 0 255 0
# Observed: 255 255 255
# Failure with 1 vec4 varyings used in varying index 0
shaders@glsl-max-varyings
@@ -0,0 +1,8 @@
# Fails or timeouts, many involving a segfault.
KHR-GLES2.texture_3d.filtering.combinations.*
KHR-GLES2.texture_3d.filtering.sizes.*
# We aren't running an X server.
glx.*
max-texture-size
@@ -0,0 +1,958 @@
spec@!opengl 1.0@depth-clear-precision-check,Fail
spec@!opengl 1.0@depth-clear-precision-check@depth16,Fail
spec@!opengl 1.0@depth-clear-precision-check@depth32,Fail
spec@!opengl [email protected],Fail
# Compat mode failure
spec@!opengl 1.0@rasterpos,Fail
spec@!opengl 1.1@line-smooth-coverage,Fail
spec@!opengl 1.1@line-smooth-stipple,Fail
spec@!opengl 1.1@linestipple,Fail
spec@!opengl 1.1@linestipple@Factor 2x,Fail
spec@!opengl 1.1@linestipple@Factor 3x,Fail
spec@!opengl 1.1@linestipple@Line loop,Fail
spec@!opengl 1.1@linestipple@Line strip,Fail
spec@!opengl [email protected] cull-back pv-first,Fail
spec@!opengl [email protected] cull-front pv-first,Fail
spec@!opengl [email protected] line cull-back pv-first,Fail
spec@!opengl [email protected] line cull-front pv-first,Fail
spec@!opengl [email protected] pv-first,Fail
spec@arb_direct_state_access@gettextureimage-formats init-by-rendering,Fail
spec@arb_indirect_parameters@conditional-render,Fail
spec@arb_indirect_parameters@conditional-render@Query result: Fail. Inverted mode: No. Points drawn: 6,Fail
spec@arb_indirect_parameters@conditional-render@Query result: Pass. Inverted mode: Yes. Points drawn: 6,Fail
spec@arb_indirect_parameters@conditional-render@Query result: Fail. Inverted mode: Yes. Points drawn: 0,Fail
spec@arb_indirect_parameters@conditional-render@Query result: Pass. Inverted mode: No. Points drawn: 0,Fail
spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex,Fail
spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex@'vs_input2[1][0]' on GL_PROGRAM_INPUT,Fail
spec@arb_query_buffer_object@qbo,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIMESTAMP-ASYNC_CPU_READ_BEFORE-GL_INT,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIMESTAMP-ASYNC_CPU_READ_BEFORE-GL_UNSIGNED_INT,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIMESTAMP-SYNC_CPU_READ_AFTER_CACHE_TEST-GL_INT,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIMESTAMP-SYNC_CPU_READ_AFTER_CACHE_TEST-GL_UNSIGNED_INT,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIMESTAMP-SYNC_CPU_READ_AFTER_CACHE_TEST-GL_UNSIGNED_INT64_ARB,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIME_ELAPSED-SYNC_CPU_READ_AFTER_CACHE_TEST-GL_INT,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIME_ELAPSED-SYNC_CPU_READ_AFTER_CACHE_TEST-GL_UNSIGNED_INT,Fail
spec@arb_query_buffer_object@qbo@query-GL_TIME_ELAPSED-SYNC_CPU_READ_AFTER_CACHE_TEST-GL_UNSIGNED_INT64_ARB,Fail
spec@arb_sample_shading@samplemask 2,Fail
spec@arb_sample_shading@samplemask 2 all,Fail
spec@arb_sample_shading@samplemask 2 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 2 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 2 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 2 all@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 2 all@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 2@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 2@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask 4,Fail
spec@arb_sample_shading@samplemask 4 all,Fail
spec@arb_sample_shading@samplemask 4 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 4 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 4 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 4 all@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 4 all@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 4@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 4@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask 6,Fail
spec@arb_sample_shading@samplemask 6 all,Fail
spec@arb_sample_shading@samplemask 6 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 6 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 6 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 6 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 6 all@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 6 all@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 6@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 6@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask 8,Fail
spec@arb_sample_shading@samplemask 8 all,Fail
spec@arb_sample_shading@samplemask 8 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 8 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 8 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 8 [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 8 all@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 8 all@sample mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask [email protected] mask_in_one,Fail
spec@arb_sample_shading@samplemask 8@noms mask_in_one,Fail
spec@arb_sample_shading@samplemask 8@sample mask_in_one,Fail
spec@arb_shader_image_load_store@early-z,Fail
spec@arb_shader_image_load_store@early-z@occlusion query test/early-z pass,Fail
spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgradcube,Fail
spec@arb_texture_buffer_object@formats (fs- arb),Crash
spec@arb_texture_buffer_object@formats (vs- arb),Crash
spec@arb_texture_view@rendering-formats,Fail
spec@arb_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_R32F,Fail
spec@arb_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RG16F,Fail
spec@arb_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RG16I,Fail
spec@arb_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RG16_SNORM,Fail
spec@arb_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RGBA8I,Fail
spec@arb_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RGBA8_SNORM,Fail
spec@egl_ext_protected_content@conformance,Fail
spec@egl 1.4@eglterminate then unbind context,Fail
spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail
# "eglInitialize() failed"
spec@egl_khr_surfaceless_context@viewport,Fail
spec@ext_external_objects@vk-semaphores,Fail
spec@ext_framebuffer_blit@fbo-blit-check-limits,Fail
spec@ext_image_dma_buf_import@ext_image_dma_buf_import-export-tex,Fail
# "Testing GL_LUMINANCE8_SNORM
# Expected: (1, 1, 1, 0)
# Actual: (1, 1, 1, 1)"
spec@ext_packed_float@query-rgba-signed-components,Fail
spec@ext_transform_feedback@tessellation triangle_fan flat_first,Fail
# due to point size clamping in shaders since hw doesn't support it later.
spec@ext_transform_feedback@builtin-varyings gl_pointsize,Fail
[email protected]@execution@geometry@primitive-types gl_line_loop,Fail
# Compat mode failures
[email protected]@execution@primitive-id-no-gs-quads,Fail
[email protected]@execution@primitive-id-no-gs-quad-strip,Fail
spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail
spec@khr_texture_compression_astc@miptree-gl srgb-fp@sRGB decode full precision,Fail
spec@khr_texture_compression_astc@miptree-gles srgb-fp,Fail
spec@khr_texture_compression_astc@miptree-gles srgb-fp@sRGB decode full precision,Fail
spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp,Fail
spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp@sRGB decode full precision,Fail
spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp,Fail
spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp@sRGB decode full precision,Fail
spec@oes_texture_view@rendering-formats,Fail
spec@oes_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_R32F,Fail
spec@oes_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RG16F,Fail
spec@oes_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RG16I,Fail
spec@oes_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RG16_SNORM,Fail
spec@oes_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RGBA8I,Fail
spec@oes_texture_view@rendering-formats@clear GL_RGB10_A2 as GL_RGBA8_SNORM,Fail
KHR-GL46.direct_state_access.renderbuffers_storage_multisample,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_r16i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_r32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_r8i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rg16i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rg32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rg8i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rgb32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rgba16i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rgba32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_2d_rgba8i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_r16i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_r32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_r8i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rg16i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rg32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rg8i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rgb32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rgba16i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rgba32i,Fail
KHR-GL46.direct_state_access.textures_storage_multisample_3d_rgba8i,Fail
# glcts: ../src/compiler/nir/nir.h:127: nir_component_mask: Assertion `nir_num_components_valid(num_components)' failed.
KHR-GL46.gpu_shader_fp64.fp64.state_query,Crash
KHR-GL46.sample_shading.render.rgba8i.full,Fail
KHR-GL46.sample_shading.render.rgba8i.half,Fail
KHR-GL46.sample_shading.render.rgba8i.none,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_0,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_1,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_2,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_3,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_4,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_5,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_6,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_7,Fail
KHR-GL46.sample_variables.mask.rgba8i.samples_1.mask_zero,Fail
# https://gitlab.freedesktop.org/mesa/mesa/-/issues/8900
KHR-GL46.shader_texture_image_samples_tests.texture_functional_test,Fail
KHR-GL46.shader_multisample_interpolation.render.base.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.centroid.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.interpolate_at_centroid.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.interpolate_at_centroid_check.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.interpolate_at_offset.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.interpolate_at_offset_check.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.interpolate_at_sample.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.interpolate_at_sample_check.rgba8i.samples_1,Fail
KHR-GL46.shader_multisample_interpolation.render.sample.rgba8i.samples_1,Fail
# "glcts: ../src/intel/compiler/brw_vec4_generator.cpp:2254: void generate_code(brw_codegen*, const brw_compiler*, void*, const nir_shader*, brw_vue_prog_data*, const cfg_t*, const brw::performance&, brw_compile_stats*, bool): Assertion `validated' failed."
KHR-GL46.shading_language_420pack.binding_samplers,Crash
KHR-GL46.texture_size_promotion.functional,Fail
KHR-GLES31.core.sample_shading.render.rgba8i.full,Fail
KHR-GLES31.core.sample_shading.render.rgba8i.half,Fail
KHR-GLES31.core.sample_shading.render.rgba8i.none,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_0,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_1,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_2,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_3,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_4,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_5,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_6,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_7,Fail
KHR-GLES31.core.sample_variables.mask.rgba8i.samples_1.mask_zero,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.base.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.centroid.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.interpolate_at_centroid.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.interpolate_at_centroid_check.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.interpolate_at_offset.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.interpolate_at_offset_check.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.interpolate_at_sample.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.interpolate_at_sample_check.rgba8i.samples_1,Fail
KHR-GLES31.core.shader_multisample_interpolation.render.sample.rgba8i.samples_1,Fail
KHR-GLES31.core.texture_storage_multisample.APIDependencies.renderbuffer_storage_multisample_invalid_samples_argument_for_integer_internalformats,Fail
dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_1_texture_int_2d,Fail
dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_1_texture_int_2d_array,Fail
dEQP-GLES31.functional.texture.multisample.samples_1.use_texture_int_2d,Fail
dEQP-GLES31.functional.texture.multisample.samples_1.use_texture_int_2d_array,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16UI/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16UI/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16_SNORM/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R16_SNORM/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R32F/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R32F/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8UI/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_R8_SNORM/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_R32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16UI/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16UI/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16_SNORM/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG16_SNORM/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32F/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32F/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RG32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RG32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32UI/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG32UI/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8UI/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8UI/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8_SNORM/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RG8_SNORM/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16UI/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB16_SNORM/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB32F/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB32I/Destination: GL_RGB32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB32I/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB32I/Destination: GL_RGB32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB32UI/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8UI/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGB8_SNORM/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RG32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RG32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16UI/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16UI/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16_SNORM/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA16_SNORM/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA32F/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA32I/Destination: GL_RGBA32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA32I/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA32I/Destination: GL_RGBA32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA32UI/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_R32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8UI/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8UI/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8_SNORM/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=2@Source: GL_RGBA8_SNORM/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16UI/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16UI/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16_SNORM/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R16_SNORM/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R32F/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R32F/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8UI/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_R8_SNORM/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_R32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16UI/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16UI/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16_SNORM/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG16_SNORM/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32F/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32F/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RG32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RG32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32UI/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG32UI/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8UI/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8UI/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8_SNORM/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RG8_SNORM/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16UI/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB16_SNORM/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB32F/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB32I/Destination: GL_RGB32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB32I/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB32I/Destination: GL_RGB32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB32UI/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8UI/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGB8_SNORM/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RG32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RG32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16UI/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16UI/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16_SNORM/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA16_SNORM/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA32F/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA32I/Destination: GL_RGBA32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA32I/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA32I/Destination: GL_RGBA32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA32UI/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_R32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8UI/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8UI/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8_SNORM/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=4@Source: GL_RGBA8_SNORM/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16UI/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16UI/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16_SNORM/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R16_SNORM/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R32F/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R32F/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8UI/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_R8_SNORM/Destination: GL_R8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_R32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16UI/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16UI/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16_SNORM/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG16_SNORM/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32F/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32F/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RG32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RG32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32UI/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG32UI/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8UI/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8UI/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8_SNORM/Destination: GL_R16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RG8_SNORM/Destination: GL_RG8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16UI/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB16_SNORM/Destination: GL_RGB16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB32F/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB32I/Destination: GL_RGB32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB32I/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB32I/Destination: GL_RGB32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB32UI/Destination: GL_RGB32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8UI/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGB8_SNORM/Destination: GL_RGB8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RG32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RG32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16UI/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16UI/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16_SNORM/Destination: GL_RG32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA16_SNORM/Destination: GL_RGBA16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA32F/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA32I/Destination: GL_RGBA32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA32I/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA32I/Destination: GL_RGBA32UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA32UI/Destination: GL_RGBA32I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_R32F,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8UI,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8_SNORM,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8UI/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8UI/Destination: GL_RGBA8I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8_SNORM/Destination: GL_RG16I,Fail
spec@arb_copy_image@arb_copy_image-formats --samples=8@Source: GL_RGBA8_SNORM/Destination: GL_RGBA8I,Fail
spec@arb_texture_multisample@texturesize@fs-texturesize-isampler2dms,Fail
spec@arb_texture_multisample@texturesize@fs-texturesize-isampler2dmsarray,Fail
spec@arb_texture_multisample@texturesize@gs-texturesize-isampler2dms,Fail
spec@arb_texture_multisample@texturesize@gs-texturesize-isampler2dmsarray,Fail
spec@arb_texture_multisample@texturesize@tes-texturesize-isampler2dms,Fail
spec@arb_texture_multisample@texturesize@tes-texturesize-isampler2dmsarray,Fail
spec@arb_texture_multisample@texturesize@vs-texturesize-isampler2dms,Fail
spec@arb_texture_multisample@texturesize@vs-texturesize-isampler2dmsarray,Fail
spec@arb_texture_rg@multisample-fast-clear gl_arb_texture_rg-int,Fail
spec@ext_shader_framebuffer_fetch_non_coherent@execution@gles3@integer-ms2,Fail
spec@ext_shader_framebuffer_fetch_non_coherent@execution@gles3@integer-ms8,Fail
spec@ext_texture_integer@multisample-fast-clear gl_ext_texture_integer,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_R16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16I/Destination: GL_RG8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16UI/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16UI/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16_SNORM/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R16_SNORM/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R32F/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R32F/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8I/Destination: GL_R8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8UI/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_R8_SNORM/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_R32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RG16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16I/Destination: GL_RGBA8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16UI/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16UI/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16_SNORM/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG16_SNORM/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32F/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32F/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RG32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RG32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32I/Destination: GL_RGBA16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32UI/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG32UI/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_R16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8I/Destination: GL_RG8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8UI/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8UI/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8_SNORM/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RG8_SNORM/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16I/Destination: GL_RGB16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16UI/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB16_SNORM/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB32F/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB32I/Destination: GL_RGB32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB32I/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB32I/Destination: GL_RGB32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB32UI/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8I/Destination: GL_RGB8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8UI/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGB8_SNORM/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RG32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RG32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16I/Destination: GL_RGBA16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16UI/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16UI/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16_SNORM/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA16_SNORM/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA32F/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA32I/Destination: GL_RGBA32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA32I/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA32I/Destination: GL_RGBA32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA32UI/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_R32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RG16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8I/Destination: GL_RGBA8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8UI/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8UI/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8_SNORM/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=2@Source: GL_RGBA8_SNORM/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_R16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16I/Destination: GL_RG8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16UI/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16UI/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16_SNORM/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R16_SNORM/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R32F/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R32F/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8I/Destination: GL_R8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8UI/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_R8_SNORM/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_R32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RG16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16I/Destination: GL_RGBA8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16UI/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16UI/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16_SNORM/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG16_SNORM/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32F/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32F/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RG32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RG32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32I/Destination: GL_RGBA16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32UI/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG32UI/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_R16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8I/Destination: GL_RG8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8UI/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8UI/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8_SNORM/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RG8_SNORM/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16I/Destination: GL_RGB16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16UI/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB16_SNORM/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB32F/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB32I/Destination: GL_RGB32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB32I/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB32I/Destination: GL_RGB32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB32UI/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8I/Destination: GL_RGB8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8UI/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGB8_SNORM/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RG32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RG32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16I/Destination: GL_RGBA16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16UI/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16UI/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16_SNORM/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA16_SNORM/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA32F/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA32I/Destination: GL_RGBA32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA32I/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA32I/Destination: GL_RGBA32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA32UI/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_R32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RG16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8I/Destination: GL_RGBA8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8UI/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8UI/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8_SNORM/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=4@Source: GL_RGBA8_SNORM/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_R16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16I/Destination: GL_RG8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16UI/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16UI/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16_SNORM/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R16_SNORM/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R32F/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R32F/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8I/Destination: GL_R8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8UI/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_R8_SNORM/Destination: GL_R8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_R32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RG16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16I/Destination: GL_RGBA8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16UI/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16UI/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16_SNORM/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG16_SNORM/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32F/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32F/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RG32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RG32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32I/Destination: GL_RGBA16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32UI/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG32UI/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_R16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8I/Destination: GL_RG8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8UI/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8UI/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8_SNORM/Destination: GL_R16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RG8_SNORM/Destination: GL_RG8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16I/Destination: GL_RGB16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16UI/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB16_SNORM/Destination: GL_RGB16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB32F/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB32I/Destination: GL_RGB32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB32I/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB32I/Destination: GL_RGB32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB32UI/Destination: GL_RGB32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8I/Destination: GL_RGB8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8UI/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGB8_SNORM/Destination: GL_RGB8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RG32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RG32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16I/Destination: GL_RGBA16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16UI/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16UI/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16_SNORM/Destination: GL_RG32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA16_SNORM/Destination: GL_RGBA16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA32F/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA32I/Destination: GL_RGBA32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA32I/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA32I/Destination: GL_RGBA32UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA32UI/Destination: GL_RGBA32I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_R32F,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RG16_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8UI,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8I/Destination: GL_RGBA8_SNORM,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8UI/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8UI/Destination: GL_RGBA8I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8_SNORM/Destination: GL_RG16I,Fail
spec@nv_copy_image@nv_copy_image-formats --samples=8@Source: GL_RGBA8_SNORM/Destination: GL_RGBA8I,Fail
# https://gitlab.freedesktop.org/mesa/mesa/-/issues/8348
KHR-GL46.tessellation_shader.tessellation_control_to_tessellation_evaluation.gl_tessLevel,Fail
KHR-GL46.tessellation_shader.tessellation_shader_tessellation.TES,Fail
spec@arb_tessellation_shader@execution@vs-tes-tessinner-tessouter-inputs-quads,Fail
spec@arb_tessellation_shader@execution@vs-tes-tessinner-tessouter-inputs-quads-dlist,Fail
spec@arb_tessellation_shader@execution@vs-tes-tessinner-tessouter-inputs-tris,Fail
@@ -0,0 +1,13 @@
KHR-GL46.texture_barrier.overlapping-texels
KHR-GL46.texture_barrier_ARB.overlapping-texels
KHR-GL46.texture_barrier_ARB.same-texel-rw-multipass
KHR-GL46.texture_barrier.same-texel-rw-multipass
KHR-GL46.tessellation_shader.tessellation_shader_tc_barriers.barrier_guarded_read_write_calls
KHR-GLES31.core.tessellation_shader.tessellation_shader_tc_barriers.barrier_guarded_read_write_calls
spec@arb_query_buffer_object@qbo
spec@arb_shader_storage_buffer_object@execution@ssbo-atomicexchange-int
spec@amd_performance_monitor@measure
spec@amd_performance_monitor@measure@change counters while active
spec@amd_performance_monitor@measure@counters in range
spec@!opengl [email protected] 100000 varray .*
@@ -0,0 +1,10 @@
# We aren't running an X server.
glx.*
# Very slow tests, potentially timing out
KHR-GL46.copy_image.functional
KHR-GL46.texture_swizzle.functional
KHR-GL46.texture_swizzle.smoke
KHR-GL46.direct_state_access.framebuffers_texture_layer_attachment
shaders@glsl-max-varyings
spec@amd_performance_monitor@measure
@@ -0,0 +1,30 @@
[[deqp]]
deqp = "/deqp-gles/modules/gles2/deqp-gles2"
caselists = ["/deqp-gles/mustpass/gles2-main.txt"]
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden"
]
version_check = "GL ES 2.0.*git"
renderer_check = "Intel.*G41"
[[deqp]]
deqp = "/deqp-gles/external/openglcts/modules/glcts"
caselists = ["/deqp-gles/mustpass/gles2-khr-main.txt"]
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden"
]
[[piglit]]
piglit_folder = "/piglit"
# We use "gpu" to skip running glslparser tests, with the assumption that
# they're covered by the llvmpipe run.
profile = "gpu"
process_isolation = true
@@ -0,0 +1,69 @@
[[deqp]]
deqp = "/deqp-gles/modules/gles2/deqp-gles2"
caselists = ["/deqp-gles/mustpass/gles2-main.txt"]
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden"
]
version_check = "GL ES 3.2.*git"
renderer_check = "Intel.*HSW GT2"
[[deqp]]
deqp = "/deqp-gles/modules/gles3/deqp-gles3"
caselists = ["/deqp-gles/mustpass/gles3-main.txt"]
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden"
]
version_check = "GL ES 3.2.*git"
renderer_check = "Intel.*HSW GT2"
[[deqp]]
deqp = "/deqp-gles/modules/gles31/deqp-gles31"
caselists = ["/deqp-gles/mustpass/gles31-main.txt"]
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden"
]
version_check = "GL ES 3.2.*git"
renderer_check = "Intel.*HSW GT2"
[[deqp]]
deqp = "/deqp-gles/external/openglcts/modules/glcts"
caselists = [
"/deqp-gles/mustpass/gles2-khr-main.txt",
"/deqp-gles/mustpass/gles3-khr-main.txt",
"/deqp-gles/mustpass/gles31-khr-main.txt"
]
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden"
]
[[deqp]]
deqp = "/deqp-gl/external/openglcts/modules/glcts"
caselists = ["/deqp-gl/mustpass/gl46-main.txt"]
deqp_args = [
"--deqp-surface-width=256", "--deqp-surface-height=256",
"--deqp-surface-type=pbuffer", "--deqp-visibility=hidden",
"--deqp-gl-config-name=rgba8888d24s8ms0",
]
[[piglit]]
piglit_folder = "/piglit"
# We use "gpu" to skip running glslparser tests, with the assumption that
# they're covered by the llvmpipe run.
profile = "gpu"
process_isolation = true
@@ -0,0 +1,37 @@
# Manual test rules for using anholt's shared g41.
.anholt-g41-test:
extends:
- .crocus-manual-rules
tags:
- anholt-g41
variables:
GPU_VERSION: crocus-g41
FLAKES_CHANNEL: "#intel-ci"
# Manual test rules for using anholt's shared hsw.
.anholt-hsw-test:
tags:
- anholt-hsw
variables:
FDO_CI_CONCURRENT: 12
# System is dead at the moment. needs maintenance.
.crocus-g41:
extends:
- .anholt-g41-test
- .test-gl
- .test-piglit
- .deqp-test
variables:
DEQP_SUITE: crocus-g41
PIGLIT_PLATFORM: gbm
.crocus-g41-traces:
extends:
- .anholt-g41-test
- .test-gl
- .piglit-traces-test
variables:
EGL_PLATFORM: "surfaceless"
PIGLIT_TRACES_FILE: traces-crocus.yml
PIGLIT_REPLAY_DEVICE_NAME: "crocus-g41"
@@ -0,0 +1,25 @@
include:
- local: 'src/gallium/drivers/crocus/ci/gitlab-ci-inc.yml'
.crocus-hsw:
extends:
- .anholt-hsw-test
- .test-gl
- .deqp-test
- .test-piglit
- .crocus-manual-rules
variables:
GPU_VERSION: crocus-hsw
DEQP_SUITE: crocus-hsw
PIGLIT_PLATFORM: gbm
.crocus-hsw-traces:
extends:
- .anholt-hsw-test
- .test-gl
- .piglit-traces-test
- .crocus-manual-rules
variables:
EGL_PLATFORM: "surfaceless"
PIGLIT_TRACES_FILE: traces-crocus.yml
PIGLIT_REPLAY_DEVICE_NAME: "crocus-hsw"
@@ -0,0 +1,176 @@
%YAML 1.2
---
traces-db:
download-url: "https://s3.freedesktop.org/mesa-tracie-public/"
traces:
0ad/0ad-v2.trace:
crocus-g41:
checksum: f4f723a73fde41b8a00a2a6518190adf
crocus-hsw:
checksum: 3ba17078e281e3d73a0e2d5d72ebf869
behdad-glyphy/glyphy-v2.trace:
crocus-g41:
label: [skip, flakes, broken]
crocus-hsw:
checksum: 49c62d99a21de18a3e184a57bf655849
glxgears/glxgears-2-v2.trace:
crocus-g41:
checksum: 18455018dcfa97f69c967f118551ae30
crocus-hsw:
checksum: f53ac20e17da91c0359c31f2fa3f401e
gputest/furmark-v2.trace:
crocus-g41:
checksum: c7c3df989f88852e88bef101b5c1dc22
crocus-hsw:
checksum: bb84373a69751942956d2320cff6dd1d
# gimark requires an environment var to work around a bug, disable for now
# gputest/gimark-v2.trace:
# crocus-g41:
# label: [unsupported]
# crocus-hsw:
# label: [skip, flakes]
# text: lighting comes in from a different direction than on freedreno?
gputest/pixmark-julia-fp32-v2.trace:
crocus-g41:
checksum: 03776a063ee7049256acd414239a7f13
crocus-hsw:
checksum: dea71222007af1669cff54ce5e0b8c8d
gputest/pixmark-julia-fp64-v2.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: 7e4948c361528a7873dad9712f629770
gputest/pixmark-volplosion-v2.trace:
crocus-g41:
checksum: 6fc94a69b9e1f38693ea3ed4f530c7da
crocus-hsw:
checksum: b96cddb97eb0cde8a388dad76d8dfef6
humus/AmbientAperture-v2.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: 5686175a74f9ef6a3b13d30f1bd32b16
humus/CelShading-v2.trace:
crocus-g41:
checksum: 9b6e185ac8e8e67fc13d84f0ad6c3e3b
crocus-hsw:
checksum: 0f03835fd89b615542ece4bbb4712e48
humus/DynamicBranching3-v2.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: 16e3458485d1ba75fe80f61f59d124be
humus/HDR-v2.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: 0dfbc65adca38721831ffddf0ede2af6
humus/Portals-v2.trace:
crocus-g41:
checksum: b090e734ed332e259664851576925d7b
crocus-hsw:
checksum: 61ea77324581e86cf8d313fe3fb27270
humus/RaytracedShadows-v2.trace:
crocus-g41:
checksum: dbef340424f4f85eb8dc053ad3a56ae1
crocus-hsw:
checksum: bac350df35b9262efca6722faf5c4eaa
humus/VolumetricFogging2-v2.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: a4f444b6ca337901ae080d8f2af812b4
neverball/neverball-v2.trace:
crocus-g41:
checksum: 0f14a88f511cd886c920238c80017e5d
crocus-hsw:
checksum: d77b3697a9b1a47611cde275aa6cb912
text: "https://gitlab.freedesktop.org/mesa/mesa/-/issues/9159"
paraview/pv-manyspheres-v2.trace:
crocus-hsw:
checksum: 73e5d34fb13268b0c7126297bfc34965
paraview/pv-waveletcontour-v2.trace:
crocus-hsw:
checksum: b384e3e81e4843fbd1d50e0c542e600a
paraview/pv-waveletvolume-v2.trace:
crocus-hsw:
checksum: 6ad068ac9f390bf42ab9e2db880ad07b
pathfinder/canvas_moire-v2.trace:
crocus-hsw:
checksum: 21bccd42f2deb6416cf6591cd6a99258
pathfinder/canvas_text_v2-v2.trace:
crocus-hsw:
checksum: 448886e3b24f6408e013ea13f7c96d28
pathfinder/demo-v2.trace:
crocus-hsw:
checksum: d9b33f0a2efe17c21b7933242afd9ec7
supertuxkart/supertuxkart-mansion-egl-gles-v2.trace:
crocus-hsw:
checksum: c59dc93744d2dfcf172aa3f26ce2a62e
valve/counterstrike-v2.trace:
crocus-g41:
checksum: 90c01e73b3544cb477ac6109bc61bef1
crocus-hsw:
checksum: 0e1e52aaccd94a261cf9d8675039c41c
valve/counterstrike-source-v2.trace:
crocus-g41:
checksum: c51e21aada8e79fada36048e7d8de74a
crocus-hsw:
checksum: a78be6d590dd6c48bc6ad6090d88d9b3
valve/half-life-2-v2.trace:
crocus-g41:
checksum: c67b47eeefb2b7a3b6667844758d4a95
crocus-hsw:
checksum: 96dcdfa2fc7e64b8bd2da0ea7b854f6c
valve/portal-2-v2.trace:
crocus-g41:
checksum: fff536c4fb7753d5cf1896c4ad4c4452
crocus-hsw:
checksum: 3c9cea7f98d8e5ab93d69c4834b570c9
xonotic/xonotic-keybench-high-v2.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
label: [skip, flakes]
ror/ror-default.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: 197eba64053d9ef096a40950163adcce
nheko/nheko-colors.trace:
crocus-g41:
checksum: 3f4bfa1516e50194e4e86978420852c4
crocus-hsw:
checksum: 7a8b329f50653480eda50f53d715ad27
blender/blender-demo-cube_diorama.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
label: [skip, flakes]
checksum: f8cc19569c0c5a43cc4f16414167d234
text: Inconsistent rendering.
blender/blender-demo-ellie_pose.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: c07530897dc5a6882cbf35737334336b
unvanquished/unvanquished-lowest.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
label: [skip, flakes]
checksum: 884096b6dd40e2f500d0837501287fac
text: "https://gitlab.freedesktop.org/mesa/mesa/-/issues/7158"
unvanquished/unvanquished-ultra.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
label: [skip, flakes]
checksum: 99b3ec85e4b9335c3cffc49a63c0c62c
text: "Text glyphs render incorrectly sometimes."
warzone2100/warzone2100-default.trace:
crocus-g41:
label: [unsupported]
crocus-hsw:
checksum: 2548cf2f42ac7bbdf5d1b26fc2f1c5f5
File diff suppressed because it is too large. Load diff
+325
View File
@@ -0,0 +1,325 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef CROCUS_BATCH_DOT_H
#define CROCUS_BATCH_DOT_H
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "util/u_dynarray.h"
#include "decoder/intel_decoder.h"
#include "drm-uapi/i915_drm.h"
#include "crocus_fence.h"
#include "crocus_fine_fence.h"
#include "crocus_bufmgr.h"
/* The kernel assumes batchbuffers are smaller than 256kB. */
#define MAX_BATCH_SIZE (256 * 1024)
/* 3DSTATE_BINDING_TABLE_POINTERS has a U16 offset from Surface State Base
* Address, which means that we can't put binding tables beyond 64kB. This
* effectively limits the maximum statebuffer size to 64kB.
*/
#define MAX_STATE_SIZE (64 * 1024)
/* Our target batch size - flush approximately at this point. */
#define BATCH_SZ (20 * 1024)
#define STATE_SZ (16 * 1024)
enum crocus_batch_name {
CROCUS_BATCH_RENDER,
CROCUS_BATCH_COMPUTE,
};
#define CROCUS_BATCH_COUNT 2
struct crocus_address {
struct crocus_bo *bo;
int32_t offset;
uint32_t reloc_flags;
};
struct crocus_reloc_list {
struct drm_i915_gem_relocation_entry *relocs;
int reloc_count;
int reloc_array_size;
};
struct crocus_growing_bo {
struct crocus_bo *bo;
void *map;
void *map_next;
struct crocus_bo *partial_bo;
void *partial_bo_map;
unsigned partial_bytes;
struct crocus_reloc_list relocs;
unsigned used;
};
struct crocus_batch {
struct crocus_context *ice;
struct crocus_screen *screen;
struct util_debug_callback *dbg;
struct pipe_device_reset_callback *reset;
/** What batch is this? (e.g. CROCUS_BATCH_RENDER/COMPUTE) */
enum crocus_batch_name name;
/** buffers: command, state */
struct crocus_growing_bo command, state;
/** Size of the primary batch if we've moved on to a secondary. */
unsigned primary_batch_size;
bool state_base_address_emitted;
uint8_t pipe_controls_since_last_cs_stall;
uint32_t hw_ctx_id;
uint32_t valid_reloc_flags;
bool use_shadow_copy;
bool no_wrap;
/** The validation list */
struct drm_i915_gem_exec_object2 *validation_list;
struct crocus_bo **exec_bos;
int exec_count;
int exec_array_size;
/** Whether INTEL_BLACKHOLE_RENDER is enabled in the batch (aka first
* instruction is a MI_BATCH_BUFFER_END).
*/
bool noop_enabled;
/**
* A list of crocus_syncobjs associated with this batch.
*
* The first list entry will always be a signalling sync-point, indicating
* that this batch has completed. The others are likely to be sync-points
* to wait on before executing the batch.
*/
struct util_dynarray syncobjs;
/** A list of drm_i915_exec_fences to have execbuf signal or wait on */
struct util_dynarray exec_fences;
/** The amount of aperture space (in bytes) used by all exec_bos */
int aperture_space;
struct {
/** Uploader to use for sequence numbers */
struct u_upload_mgr *uploader;
/** GPU buffer and CPU map where our seqno's will be written. */
struct crocus_state_ref ref;
uint32_t *map;
/** The sequence number to write the next time we add a fence. */
uint32_t next;
} fine_fences;
/** A seqno (and syncobj) for the last batch that was submitted. */
struct crocus_fine_fence *last_fence;
/** List of other batches which we might need to flush to use a BO */
struct crocus_batch *other_batches[CROCUS_BATCH_COUNT - 1];
struct {
/**
* Set of struct brw_bo * that have been rendered to within this
* batchbuffer and would need flushing before being used from another
* cache domain that isn't coherent with it (i.e. the sampler).
*/
struct hash_table *render;
/**
* Set of struct brw_bo * that have been used as a depth buffer within
* this batchbuffer and would need flushing before being used from
* another cache domain that isn't coherent with it (i.e. the sampler).
*/
struct set *depth;
} cache;
struct intel_batch_decode_ctx decoder;
struct hash_table_u64 *state_sizes;
/** Have we emitted any draw calls to this batch? */
bool contains_draw;
/** Batch contains fence signal operation. */
bool contains_fence_signal;
};
static inline bool
batch_has_fine_fence(struct crocus_batch *batch)
{
return !!batch->fine_fences.uploader;
}
#define BATCH_HAS_FINE_FENCES(batch) (!!(batch)->fine_fences.uploader)
void crocus_init_batch(struct crocus_context *ctx,
enum crocus_batch_name name,
int priority);
void crocus_batch_free(struct crocus_batch *batch);
void crocus_batch_maybe_flush(struct crocus_batch *batch, unsigned estimate);
void _crocus_batch_flush(struct crocus_batch *batch, const char *file, int line);
#define crocus_batch_flush(batch) _crocus_batch_flush((batch), __FILE__, __LINE__)
bool crocus_batch_references(struct crocus_batch *batch, struct crocus_bo *bo);
bool crocus_batch_prepare_noop(struct crocus_batch *batch, bool noop_enable);
#define RELOC_WRITE EXEC_OBJECT_WRITE
#define RELOC_NEEDS_GGTT EXEC_OBJECT_NEEDS_GTT
/* Inverted meaning, but using the same bit...emit_reloc will flip it. */
#define RELOC_32BIT EXEC_OBJECT_SUPPORTS_48B_ADDRESS
void crocus_use_pinned_bo(struct crocus_batch *batch, struct crocus_bo *bo,
bool writable);
uint64_t crocus_command_reloc(struct crocus_batch *batch, uint32_t batch_offset,
struct crocus_bo *target, uint32_t target_offset,
unsigned int reloc_flags);
uint64_t crocus_state_reloc(struct crocus_batch *batch, uint32_t batch_offset,
struct crocus_bo *target, uint32_t target_offset,
unsigned int reloc_flags);
enum pipe_reset_status crocus_batch_check_for_reset(struct crocus_batch *batch);
void crocus_grow_buffer(struct crocus_batch *batch, bool grow_state,
unsigned used, unsigned new_size);
static inline unsigned
crocus_batch_bytes_used(struct crocus_batch *batch)
{
return batch->command.map_next - batch->command.map;
}
/**
* Ensure the current command buffer has \param size bytes of space
* remaining. If not, this creates a secondary batch buffer and emits
* a jump from the primary batch to the start of the secondary.
*
* Most callers want crocus_get_command_space() instead.
*/
static inline void
crocus_require_command_space(struct crocus_batch *batch, unsigned size)
{
const unsigned required_bytes = crocus_batch_bytes_used(batch) + size;
unsigned used = crocus_batch_bytes_used(batch);
if (required_bytes >= BATCH_SZ && !batch->no_wrap) {
crocus_batch_flush(batch);
} else if (used + size >= batch->command.bo->size) {
const unsigned new_size =
MIN2(batch->command.bo->size + batch->command.bo->size / 2,
MAX_BATCH_SIZE);
crocus_grow_buffer(batch, false, used, new_size);
batch->command.map_next = (void *)batch->command.map + used;
assert(crocus_batch_bytes_used(batch) + size < batch->command.bo->size);
}
}
/**
* Allocate space in the current command buffer, and return a pointer
* to the mapped area so the caller can write commands there.
*
* This should be called whenever emitting commands.
*/
static inline void *
crocus_get_command_space(struct crocus_batch *batch, unsigned bytes)
{
crocus_require_command_space(batch, bytes);
void *map = batch->command.map_next;
batch->command.map_next += bytes;
return map;
}
/**
* Helper to emit GPU commands - allocates space, copies them there.
*/
static inline void
crocus_batch_emit(struct crocus_batch *batch, const void *data, unsigned size)
{
void *map = crocus_get_command_space(batch, size);
memcpy(map, data, size);
}
/**
* Get a pointer to the batch's signalling syncobj. Does not refcount.
*/
static inline struct crocus_syncobj *
crocus_batch_get_signal_syncobj(struct crocus_batch *batch)
{
/* The signalling syncobj is the first one in the list. */
struct crocus_syncobj *syncobj =
((struct crocus_syncobj **)util_dynarray_begin(&batch->syncobjs))[0];
return syncobj;
}
/**
* Take a reference to the batch's signalling syncobj.
*
* Callers can use this to wait for the the current batch under construction
* to complete (after flushing it).
*/
static inline void
crocus_batch_reference_signal_syncobj(struct crocus_batch *batch,
struct crocus_syncobj **out_syncobj)
{
struct crocus_syncobj *syncobj = crocus_batch_get_signal_syncobj(batch);
crocus_syncobj_reference(batch->screen, out_syncobj, syncobj);
}
/**
* Record the size of a piece of state for use in INTEL_DEBUG=bat printing.
*/
static inline void
crocus_record_state_size(struct hash_table_u64 *ht, uint32_t offset_from_base,
uint32_t size)
{
if (ht) {
_mesa_hash_table_u64_insert(ht, offset_from_base,
(void *)(uintptr_t)size);
}
}
static inline bool
crocus_ptr_in_state_buffer(struct crocus_batch *batch, void *p)
{
return (char *)p >= (char *)batch->state.map &&
(char *)p < (char *)batch->state.map + batch->state.bo->size;
}
static inline void
crocus_require_statebuffer_space(struct crocus_batch *batch, int size)
{
if (batch->state.used + size >= STATE_SZ)
crocus_batch_flush(batch);
}
#endif
+803
View File
@@ -0,0 +1,803 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/format/u_format.h"
#include "util/u_inlines.h"
#include "util/u_surface.h"
#include "util/ralloc.h"
#include "intel/blorp/blorp.h"
#include "crocus_context.h"
#include "crocus_resource.h"
#include "crocus_screen.h"
void crocus_blitter_begin(struct crocus_context *ice, enum crocus_blitter_op op, bool render_cond)
{
util_blitter_save_vertex_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_VERTEX]);
util_blitter_save_tessctrl_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_TESS_CTRL]);
util_blitter_save_tesseval_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL]);
util_blitter_save_geometry_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_GEOMETRY]);
util_blitter_save_so_targets(ice->blitter, ice->state.so_targets,
(struct pipe_stream_output_target**)ice->state.so_target, MESA_PRIM_UNKNOWN);
util_blitter_save_vertex_buffers(ice->blitter, ice->state.vertex_buffers,
util_last_bit(ice->state.bound_vertex_buffers));
util_blitter_save_vertex_elements(ice->blitter, (void *)ice->state.cso_vertex_elements);
if (op & CROCUS_SAVE_FRAGMENT_STATE) {
util_blitter_save_blend(ice->blitter, ice->state.cso_blend);
util_blitter_save_depth_stencil_alpha(ice->blitter, ice->state.cso_zsa);
util_blitter_save_stencil_ref(ice->blitter, &ice->state.stencil_ref);
util_blitter_save_fragment_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_FRAGMENT]);
util_blitter_save_sample_mask(ice->blitter, ice->state.sample_mask, 0);
util_blitter_save_rasterizer(ice->blitter, ice->state.cso_rast);
util_blitter_save_scissor(ice->blitter, &(struct pipe_scissor_state) {
ice->state.scissors[0].minx, ice->state.scissors[0].miny,
ice->state.scissors[0].maxx, ice->state.scissors[0].maxy });
util_blitter_save_viewport(ice->blitter, &ice->state.viewports[0]);
util_blitter_save_fragment_constant_buffer_slot(ice->blitter, &ice->state.shaders[MESA_SHADER_FRAGMENT].constbufs[0]);
}
if (!render_cond)
util_blitter_save_render_condition(ice->blitter,
(struct pipe_query *)ice->condition.query,
ice->condition.condition,
ice->condition.mode);
// util_blitter_save_scissor(ice->blitter, &ice->scissors[0]);
if (op & CROCUS_SAVE_FRAMEBUFFER)
util_blitter_save_framebuffer(ice->blitter, &ice->state.framebuffer);
if (op & CROCUS_SAVE_TEXTURES) {
util_blitter_save_fragment_sampler_states(ice->blitter, 1, (void **)ice->state.shaders[MESA_SHADER_FRAGMENT].samplers);
util_blitter_save_fragment_sampler_views(ice->blitter, 1, (struct pipe_sampler_view **)ice->state.shaders[MESA_SHADER_FRAGMENT].textures);
}
}
/**
* Helper function for handling mirror image blits.
*
* If coord0 > coord1, swap them and return "true" (mirrored).
*/
static bool
apply_mirror(float *coord0, float *coord1)
{
if (*coord0 > *coord1) {
float tmp = *coord0;
*coord0 = *coord1;
*coord1 = tmp;
return true;
}
return false;
}
/**
* Compute the number of pixels to clip for each side of a rect
*
* \param x0 The rect's left coordinate
* \param y0 The rect's bottom coordinate
* \param x1 The rect's right coordinate
* \param y1 The rect's top coordinate
* \param min_x The clipping region's left coordinate
* \param min_y The clipping region's bottom coordinate
* \param max_x The clipping region's right coordinate
* \param max_y The clipping region's top coordinate
* \param clipped_x0 The number of pixels to clip from the left side
* \param clipped_y0 The number of pixels to clip from the bottom side
* \param clipped_x1 The number of pixels to clip from the right side
* \param clipped_y1 The number of pixels to clip from the top side
*
* \return false if we clip everything away, true otherwise
*/
static inline bool
compute_pixels_clipped(float x0, float y0, float x1, float y1,
float min_x, float min_y, float max_x, float max_y,
float *clipped_x0, float *clipped_y0,
float *clipped_x1, float *clipped_y1)
{
/* If we are going to clip everything away, stop. */
if (!(min_x <= max_x &&
min_y <= max_y &&
x0 <= max_x &&
y0 <= max_y &&
min_x <= x1 &&
min_y <= y1 &&
x0 <= x1 &&
y0 <= y1)) {
return false;
}
if (x0 < min_x)
*clipped_x0 = min_x - x0;
else
*clipped_x0 = 0;
if (max_x < x1)
*clipped_x1 = x1 - max_x;
else
*clipped_x1 = 0;
if (y0 < min_y)
*clipped_y0 = min_y - y0;
else
*clipped_y0 = 0;
if (max_y < y1)
*clipped_y1 = y1 - max_y;
else
*clipped_y1 = 0;
return true;
}
/**
* Clips a coordinate (left, right, top or bottom) for the src or dst rect
* (whichever requires the largest clip) and adjusts the coordinate
* for the other rect accordingly.
*
* \param mirror true if mirroring is required
* \param src the source rect coordinate (for example src_x0)
* \param dst0 the dst rect coordinate (for example dst_x0)
* \param dst1 the opposite dst rect coordinate (for example dst_x1)
* \param clipped_dst0 number of pixels to clip from the dst coordinate
* \param clipped_dst1 number of pixels to clip from the opposite dst coordinate
* \param scale the src vs dst scale involved for that coordinate
* \param is_left_or_bottom true if we are clipping the left or bottom sides
* of the rect.
*/
static void
clip_coordinates(bool mirror,
float *src, float *dst0, float *dst1,
float clipped_dst0,
float clipped_dst1,
float scale,
bool is_left_or_bottom)
{
/* When clipping we need to add or subtract pixels from the original
* coordinates depending on whether we are acting on the left/bottom
* or right/top sides of the rect respectively. We assume we have to
* add them in the code below, and multiply by -1 when we should
* subtract.
*/
int mult = is_left_or_bottom ? 1 : -1;
if (!mirror) {
*dst0 += clipped_dst0 * mult;
*src += clipped_dst0 * scale * mult;
} else {
*dst1 -= clipped_dst1 * mult;
*src += clipped_dst1 * scale * mult;
}
}
/**
* Apply a scissor rectangle to blit coordinates.
*
* Returns true if the blit was entirely scissored away.
*/
static bool
apply_blit_scissor(const struct pipe_scissor_state *scissor,
float *src_x0, float *src_y0,
float *src_x1, float *src_y1,
float *dst_x0, float *dst_y0,
float *dst_x1, float *dst_y1,
bool mirror_x, bool mirror_y)
{
float clip_dst_x0, clip_dst_x1, clip_dst_y0, clip_dst_y1;
/* Compute number of pixels to scissor away. */
if (!compute_pixels_clipped(*dst_x0, *dst_y0, *dst_x1, *dst_y1,
scissor->minx, scissor->miny,
scissor->maxx, scissor->maxy,
&clip_dst_x0, &clip_dst_y0,
&clip_dst_x1, &clip_dst_y1))
return true;
// XXX: comments assume source clipping, which we don't do
/* When clipping any of the two rects we need to adjust the coordinates
* in the other rect considering the scaling factor involved. To obtain
* the best precision we want to make sure that we only clip once per
* side to avoid accumulating errors due to the scaling adjustment.
*
* For example, if src_x0 and dst_x0 need both to be clipped we want to
* avoid the situation where we clip src_x0 first, then adjust dst_x0
* accordingly but then we realize that the resulting dst_x0 still needs
* to be clipped, so we clip dst_x0 and adjust src_x0 again. Because we are
* applying scaling factors to adjust the coordinates in each clipping
* pass we lose some precision and that can affect the results of the
* blorp blit operation slightly. What we want to do here is detect the
* rect that we should clip first for each side so that when we adjust
* the other rect we ensure the resulting coordinate does not need to be
* clipped again.
*
* The code below implements this by comparing the number of pixels that
* we need to clip for each side of both rects considering the scales
* involved. For example, clip_src_x0 represents the number of pixels
* to be clipped for the src rect's left side, so if clip_src_x0 = 5,
* clip_dst_x0 = 4 and scale_x = 2 it means that we are clipping more
* from the dst rect so we should clip dst_x0 only and adjust src_x0.
* This is because clipping 4 pixels in the dst is equivalent to
* clipping 4 * 2 = 8 > 5 in the src.
*/
if (*src_x0 == *src_x1 || *src_y0 == *src_y1
|| *dst_x0 == *dst_x1 || *dst_y0 == *dst_y1)
return true;
float scale_x = (float) (*src_x1 - *src_x0) / (*dst_x1 - *dst_x0);
float scale_y = (float) (*src_y1 - *src_y0) / (*dst_y1 - *dst_y0);
/* Clip left side */
clip_coordinates(mirror_x, src_x0, dst_x0, dst_x1,
clip_dst_x0, clip_dst_x1, scale_x, true);
/* Clip right side */
clip_coordinates(mirror_x, src_x1, dst_x1, dst_x0,
clip_dst_x1, clip_dst_x0, scale_x, false);
/* Clip bottom side */
clip_coordinates(mirror_y, src_y0, dst_y0, dst_y1,
clip_dst_y0, clip_dst_y1, scale_y, true);
/* Clip top side */
clip_coordinates(mirror_y, src_y1, dst_y1, dst_y0,
clip_dst_y1, clip_dst_y0, scale_y, false);
/* Check for invalid bounds
* Can't blit for 0-dimensions
*/
return *src_x0 == *src_x1 || *src_y0 == *src_y1
|| *dst_x0 == *dst_x1 || *dst_y0 == *dst_y1;
}
void
crocus_blorp_surf_for_resource(struct crocus_vtable *vtbl,
struct isl_device *isl_dev,
struct blorp_surf *surf,
struct pipe_resource *p_res,
enum isl_aux_usage aux_usage,
unsigned level,
bool is_render_target)
{
struct crocus_resource *res = (void *) p_res;
if (isl_aux_usage_has_hiz(aux_usage) &&
!crocus_resource_level_has_hiz(res, level))
aux_usage = ISL_AUX_USAGE_NONE;
*surf = (struct blorp_surf) {
.surf = &res->surf,
.addr = (struct blorp_address) {
.buffer = res->bo,
.offset = res->offset,
.reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,
.mocs = crocus_mocs(res->bo, isl_dev),
},
.aux_usage = aux_usage,
};
if (aux_usage != ISL_AUX_USAGE_NONE) {
surf->aux_surf = &res->aux.surf;
surf->aux_addr = (struct blorp_address) {
.buffer = res->aux.bo,
.offset = res->aux.offset,
.reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,
.mocs = crocus_mocs(res->bo, isl_dev),
};
surf->clear_color =
crocus_resource_get_clear_color(res);
}
}
static void
tex_cache_flush_hack(struct crocus_batch *batch,
enum isl_format view_format,
enum isl_format surf_format)
{
/* The WaSamplerCacheFlushBetweenRedescribedSurfaceReads workaround says:
*
* "Currently Sampler assumes that a surface would not have two
* different format associate with it. It will not properly cache
* the different views in the MT cache, causing a data corruption."
*
* We may need to handle this for texture views in general someday, but
* for now we handle it here, as it hurts copies and blits particularly
* badly because they ofter reinterpret formats.
*
* If the BO hasn't been referenced yet this batch, we assume that the
* texture cache doesn't contain any relevant data nor need flushing.
*
* Icelake (Gen11+) claims to fix this issue, but seems to still have
* issues with ASTC formats.
*/
bool need_flush = view_format != surf_format;
if (!need_flush)
return;
const char *reason =
"workaround: WaSamplerCacheFlushBetweenRedescribedSurfaceReads";
crocus_emit_pipe_control_flush(batch, reason, PIPE_CONTROL_CS_STALL);
crocus_emit_pipe_control_flush(batch, reason,
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
}
static struct crocus_resource *
crocus_resource_for_aspect(const struct intel_device_info *devinfo,
struct pipe_resource *p_res, unsigned pipe_mask)
{
if (pipe_mask == PIPE_MASK_S) {
struct crocus_resource *junk, *s_res;
crocus_get_depth_stencil_resources(devinfo, p_res, &junk, &s_res);
return s_res;
} else {
return (struct crocus_resource *)p_res;
}
}
static enum pipe_format
pipe_format_for_aspect(enum pipe_format format, unsigned pipe_mask)
{
if (pipe_mask == PIPE_MASK_S) {
return util_format_stencil_only(format);
} else if (pipe_mask == PIPE_MASK_Z) {
return util_format_get_depth_only(format);
} else {
return format;
}
}
static void
crocus_u_blitter(struct crocus_context *ice,
const struct pipe_blit_info *info)
{
struct pipe_blit_info dinfo = *info;
if (!util_format_has_alpha(dinfo.dst.resource->format))
dinfo.mask &= ~PIPE_MASK_A;
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
util_blitter_blit(ice->blitter, &dinfo, NULL);
}
/**
* The pipe->blit() driver hook.
*
* This performs a blit between two surfaces, which copies data but may
* also perform format conversion, scaling, flipping, and so on.
*/
static void
crocus_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
{
struct crocus_context *ice = (void *) ctx;
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
const struct intel_device_info *devinfo = &screen->devinfo;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
enum blorp_batch_flags blorp_flags = 0;
/* We don't support color masking. */
assert((info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA ||
(info->mask & PIPE_MASK_RGBA) == 0);
if (info->render_condition_enable)
if (!crocus_check_conditional_render(ice))
return;
if (devinfo->ver <= 5) {
if (!screen->vtbl.blit_blt(batch, info)) {
if (!util_format_is_depth_or_stencil(info->src.resource->format) &&
info->dst.resource->target != PIPE_TEXTURE_3D)
goto use_blorp;
if (!util_blitter_is_blit_supported(ice->blitter, info)) {
if (util_format_is_depth_or_stencil(info->src.resource->format)) {
struct pipe_blit_info depth_blit = *info;
depth_blit.mask = PIPE_MASK_Z;
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
util_blitter_blit(ice->blitter, &depth_blit, NULL);
struct pipe_surface dst_templ;
util_blitter_default_dst_texture(&dst_templ, info->dst.resource, info->dst.level, info->dst.box.z);
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
util_blitter_clear_depth_stencil(ice->blitter, &dst_templ, PIPE_CLEAR_STENCIL,
0, 0, info->dst.box.x, info->dst.box.y,
info->dst.box.width, info->dst.box.height);
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
util_blitter_stencil_fallback(ice->blitter,
info->dst.resource,
info->dst.level,
&info->dst.box,
info->src.resource,
info->src.level,
&info->src.box, NULL);
}
return;
}
crocus_u_blitter(ice, info);
}
return;
}
if (devinfo->ver == 6) {
if (info->src.resource->target == PIPE_TEXTURE_3D &&
info->dst.resource->target == PIPE_TEXTURE_3D) {
crocus_u_blitter(ice, info);
return;
}
}
use_blorp:
if (info->render_condition_enable) {
if (ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT)
blorp_flags |= BLORP_BATCH_PREDICATE_ENABLE;
}
float src_x0 = info->src.box.x;
float src_x1 = info->src.box.x + info->src.box.width;
float src_y0 = info->src.box.y;
float src_y1 = info->src.box.y + info->src.box.height;
float dst_x0 = info->dst.box.x;
float dst_x1 = info->dst.box.x + info->dst.box.width;
float dst_y0 = info->dst.box.y;
float dst_y1 = info->dst.box.y + info->dst.box.height;
bool mirror_x = apply_mirror(&src_x0, &src_x1);
bool mirror_y = apply_mirror(&src_y0, &src_y1);
enum blorp_filter filter;
if (info->scissor_enable) {
bool noop = apply_blit_scissor(&info->scissor,
&src_x0, &src_y0, &src_x1, &src_y1,
&dst_x0, &dst_y0, &dst_x1, &dst_y1,
mirror_x, mirror_y);
if (noop)
return;
}
if (abs(info->dst.box.width) == abs(info->src.box.width) &&
abs(info->dst.box.height) == abs(info->src.box.height)) {
if (info->src.resource->nr_samples > 1 &&
info->dst.resource->nr_samples <= 1) {
/* The OpenGL ES 3.2 specification, section 16.2.1, says:
*
* "If the read framebuffer is multisampled (its effective
* value of SAMPLE_BUFFERS is one) and the draw framebuffer
* is not (its value of SAMPLE_BUFFERS is zero), the samples
* corresponding to each pixel location in the source are
* converted to a single sample before being written to the
* destination. The filter parameter is ignored. If the
* source formats are integer types or stencil values, a
* single sample’s value is selected for each pixel. If the
* source formats are floating-point or normalized types,
* the sample values for each pixel are resolved in an
* implementation-dependent manner. If the source formats
* are depth values, sample values are resolved in an
* implementation-dependent manner where the result will be
* between the minimum and maximum depth values in the pixel."
*
* When selecting a single sample, we always choose sample 0.
*/
if (util_format_is_depth_or_stencil(info->src.format) ||
util_format_is_pure_integer(info->src.format)) {
filter = BLORP_FILTER_SAMPLE_0;
} else {
filter = BLORP_FILTER_AVERAGE;
}
} else {
/* The OpenGL 4.6 specification, section 18.3.1, says:
*
* "If the source and destination dimensions are identical,
* no filtering is applied."
*
* Using BLORP_FILTER_NONE will also handle the upsample case by
* replicating the one value in the source to all values in the
* destination.
*/
filter = BLORP_FILTER_NONE;
}
} else if (info->filter == PIPE_TEX_FILTER_LINEAR) {
filter = BLORP_FILTER_BILINEAR;
} else {
filter = BLORP_FILTER_NEAREST;
}
struct blorp_batch blorp_batch;
blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags);
float src_z_step = (float)info->src.box.depth / (float)info->dst.box.depth;
/* There is no interpolation to the pixel center during rendering, so
* add the 0.5 offset ourselves here.
*/
float depth_center_offset = 0;
if (info->src.resource->target == PIPE_TEXTURE_3D)
depth_center_offset = 0.5 / info->dst.box.depth * info->src.box.depth;
/* Perform a blit for each aspect requested by the caller. PIPE_MASK_R is
* used to represent the color aspect. */
unsigned aspect_mask = info->mask & (PIPE_MASK_R | PIPE_MASK_ZS);
while (aspect_mask) {
unsigned aspect = 1 << u_bit_scan(&aspect_mask);
struct crocus_resource *src_res =
crocus_resource_for_aspect(devinfo, info->src.resource, aspect);
struct crocus_resource *dst_res =
crocus_resource_for_aspect(devinfo, info->dst.resource, aspect);
enum pipe_format src_pfmt =
pipe_format_for_aspect(info->src.format, aspect);
enum pipe_format dst_pfmt =
pipe_format_for_aspect(info->dst.format, aspect);
struct crocus_format_info src_fmt =
crocus_format_for_usage(devinfo, src_pfmt, ISL_SURF_USAGE_TEXTURE_BIT);
enum isl_aux_usage src_aux_usage =
crocus_resource_texture_aux_usage(src_res);
crocus_resource_prepare_texture(ice, src_res, src_fmt.fmt,
info->src.level, 1, info->src.box.z,
info->src.box.depth);
// crocus_emit_buffer_barrier_for(batch, src_res->bo,
// CROCUS_DOMAIN_OTHER_READ);
bool dst_aux_disable = false;
/* on SNB blorp will use render target instead of depth
* so disable HiZ.
*/
if (devinfo->ver <= 6 && util_format_is_depth_or_stencil(dst_pfmt))
dst_aux_disable = true;
struct crocus_format_info dst_fmt =
crocus_format_for_usage(devinfo, dst_pfmt,
ISL_SURF_USAGE_RENDER_TARGET_BIT);
enum isl_aux_usage dst_aux_usage =
crocus_resource_render_aux_usage(ice, dst_res, info->dst.level,
dst_fmt.fmt, dst_aux_disable);
struct blorp_surf src_surf, dst_surf;
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &src_surf,
&src_res->base.b, src_aux_usage,
info->src.level, false);
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &dst_surf,
&dst_res->base.b, dst_aux_usage,
info->dst.level, true);
crocus_resource_prepare_render(ice, dst_res, info->dst.level,
info->dst.box.z, info->dst.box.depth,
dst_aux_usage);
// crocus_emit_buffer_barrier_for(batch, dst_res->bo,
// CROCUS_DOMAIN_RENDER_WRITE);
if (crocus_batch_references(batch, src_res->bo))
tex_cache_flush_hack(batch, src_fmt.fmt, src_res->surf.format);
if (dst_res->base.b.target == PIPE_BUFFER) {
util_range_add(&dst_res->base.b, &dst_res->valid_buffer_range,
dst_x0, dst_x1);
}
struct isl_swizzle src_swiz = pipe_to_isl_swizzles(src_fmt.swizzles);
struct isl_swizzle dst_swiz = pipe_to_isl_swizzles(dst_fmt.swizzles);
for (int slice = 0; slice < info->dst.box.depth; slice++) {
unsigned dst_z = info->dst.box.z + slice;
float src_z = info->src.box.z + slice * src_z_step +
depth_center_offset;
crocus_batch_maybe_flush(batch, 1500);
blorp_blit(&blorp_batch,
&src_surf, info->src.level, src_z,
src_fmt.fmt, src_swiz,
&dst_surf, info->dst.level, dst_z,
dst_fmt.fmt, dst_swiz,
src_x0, src_y0, src_x1, src_y1,
dst_x0, dst_y0, dst_x1, dst_y1,
filter, mirror_x, mirror_y);
}
tex_cache_flush_hack(batch, src_fmt.fmt, src_res->surf.format);
crocus_resource_finish_render(ice, dst_res, info->dst.level,
info->dst.box.z, info->dst.box.depth,
dst_aux_usage);
}
blorp_batch_finish(&blorp_batch);
crocus_flush_and_dirty_for_history(ice, batch, (struct crocus_resource *)
info->dst.resource,
PIPE_CONTROL_RENDER_TARGET_FLUSH,
"cache history: post-blit");
}
static void
get_copy_region_aux_settings(struct crocus_resource *res,
enum isl_aux_usage *out_aux_usage,
bool is_render_target)
{
switch (res->aux.usage) {
case ISL_AUX_USAGE_MCS:
/* A stencil resolve operation must be performed prior to doing resource
* copies or used by CPU.
* (see HSD 1209978162)
*/
if (is_render_target && isl_surf_usage_is_stencil(res->surf.usage)) {
*out_aux_usage = ISL_AUX_USAGE_NONE;
} else {
*out_aux_usage = res->aux.usage;
}
break;
default:
*out_aux_usage = ISL_AUX_USAGE_NONE;
break;
}
}
/**
* Perform a GPU-based raw memory copy between compatible view classes.
*
* Does not perform any flushing - the new data may still be left in the
* render cache, and old data may remain in other caches.
*
* Wraps blorp_copy() and blorp_buffer_copy().
*/
void
crocus_copy_region(struct blorp_context *blorp,
struct crocus_batch *batch,
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 blorp_batch blorp_batch;
struct crocus_context *ice = blorp->driver_ctx;
struct crocus_screen *screen = (void *) ice->ctx.screen;
const struct intel_device_info *devinfo = &screen->devinfo;
struct crocus_resource *src_res = (void *) src;
struct crocus_resource *dst_res = (void *) dst;
if (devinfo->ver <= 5) {
if (screen->vtbl.copy_region_blt(batch, dst_res,
dst_level, dstx, dsty, dstz,
src_res, src_level, src_box))
return;
}
enum isl_aux_usage src_aux_usage, dst_aux_usage;
get_copy_region_aux_settings(src_res, &src_aux_usage,
false);
get_copy_region_aux_settings(dst_res, &dst_aux_usage,
true);
if (crocus_batch_references(batch, src_res->bo))
tex_cache_flush_hack(batch, ISL_FORMAT_UNSUPPORTED, src_res->surf.format);
if (dst->target == PIPE_BUFFER)
util_range_add(&dst_res->base.b, &dst_res->valid_buffer_range, dstx, dstx + src_box->width);
if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
struct blorp_address src_addr = {
.buffer = crocus_resource_bo(src), .offset = src_box->x,
.mocs = crocus_mocs(src_res->bo, &screen->isl_dev),
};
struct blorp_address dst_addr = {
.buffer = crocus_resource_bo(dst), .offset = dstx,
.mocs = crocus_mocs(dst_res->bo, &screen->isl_dev),
.reloc_flags = EXEC_OBJECT_WRITE,
};
crocus_batch_maybe_flush(batch, 1500);
blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
blorp_buffer_copy(&blorp_batch, src_addr, dst_addr, src_box->width);
blorp_batch_finish(&blorp_batch);
} else {
// XXX: what about one surface being a buffer and not the other?
struct blorp_surf src_surf, dst_surf;
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &src_surf,
src, src_aux_usage, src_level, false);
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &dst_surf,
dst, dst_aux_usage, dst_level, true);
crocus_resource_prepare_access(ice, src_res, src_level, 1,
src_box->z, src_box->depth,
src_aux_usage, false);
crocus_resource_prepare_access(ice, dst_res, dst_level, 1,
dstz, src_box->depth,
dst_aux_usage, false);
blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
for (int slice = 0; slice < src_box->depth; slice++) {
crocus_batch_maybe_flush(batch, 1500);
blorp_copy(&blorp_batch, &src_surf, src_level, src_box->z + slice,
&dst_surf, dst_level, dstz + slice,
src_box->x, src_box->y, dstx, dsty,
src_box->width, src_box->height);
}
blorp_batch_finish(&blorp_batch);
crocus_resource_finish_write(ice, dst_res, dst_level, dstz,
src_box->depth, dst_aux_usage);
}
tex_cache_flush_hack(batch, ISL_FORMAT_UNSUPPORTED, src_res->surf.format);
}
/**
* The pipe->resource_copy_region() driver hook.
*
* This implements ARB_copy_image semantics - a raw memory copy between
* compatible view classes.
*/
static void
crocus_resource_copy_region(struct pipe_context *ctx,
struct pipe_resource *p_dst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct pipe_resource *p_src,
unsigned src_level,
const struct pipe_box *src_box)
{
struct crocus_context *ice = (void *) ctx;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
const struct intel_device_info *devinfo = &screen->devinfo;
struct crocus_resource *dst = (void *) p_dst;
if (devinfo->ver < 6 && util_format_is_depth_or_stencil(p_dst->format)) {
util_resource_copy_region(ctx, p_dst, dst_level, dstx, dsty, dstz,
p_src, src_level, src_box);
return;
}
crocus_copy_region(&ice->blorp, batch, p_dst, dst_level, dstx, dsty, dstz,
p_src, src_level, src_box);
if (util_format_is_depth_and_stencil(p_dst->format) &&
util_format_has_stencil(util_format_description(p_src->format)) &&
devinfo->ver >= 6) {
struct crocus_resource *junk, *s_src_res, *s_dst_res;
crocus_get_depth_stencil_resources(devinfo, p_src, &junk, &s_src_res);
crocus_get_depth_stencil_resources(devinfo, p_dst, &junk, &s_dst_res);
crocus_copy_region(&ice->blorp, batch, &s_dst_res->base.b, dst_level, dstx,
dsty, dstz, &s_src_res->base.b, src_level, src_box);
}
crocus_flush_and_dirty_for_history(ice, batch, dst,
PIPE_CONTROL_RENDER_TARGET_FLUSH,
"cache history: post copy_region");
}
void
crocus_init_blit_functions(struct pipe_context *ctx)
{
ctx->blit = crocus_blit;
ctx->resource_copy_region = crocus_resource_copy_region;
}
+452
View File
@@ -0,0 +1,452 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_blorp.c
*
* ============================= GENXML CODE =============================
* [This file is compiled once per generation.]
* =======================================================================
*
* GenX specific code for working with BLORP (blitting, resolves, clears
* on the 3D engine). This provides the driver-specific hooks needed to
* implement the BLORP API.
*
* See crocus_blit.c, crocus_clear.c, and so on.
*/
#include <assert.h>
#include "crocus_batch.h"
#include "crocus_resource.h"
#include "crocus_context.h"
#include "util/u_upload_mgr.h"
#include "intel/common/intel_l3_config.h"
#include "blorp/blorp_genX_exec_elk.h"
#if GFX_VER <= 5
#include "gen4_blorp_exec.h"
#endif
static uint32_t *
stream_state(struct crocus_batch *batch,
unsigned size,
unsigned alignment,
uint32_t *out_offset,
struct crocus_bo **out_bo)
{
uint32_t offset = align(batch->state.used, alignment);
if (offset + size >= STATE_SZ && !batch->no_wrap) {
crocus_batch_flush(batch);
offset = align(batch->state.used, alignment);
} else if (offset + size >= batch->state.bo->size) {
const unsigned new_size =
MIN2(batch->state.bo->size + batch->state.bo->size / 2,
MAX_STATE_SIZE);
crocus_grow_buffer(batch, true, batch->state.used, new_size);
assert(offset + size < batch->state.bo->size);
}
crocus_record_state_size(batch->state_sizes, offset, size);
batch->state.used = offset + size;
*out_offset = offset;
/* If the caller has asked for a BO, we leave them the responsibility of
* adding bo->gtt_offset (say, by handing an address to genxml). If not,
* we assume they want the offset from a base address.
*/
if (out_bo)
*out_bo = batch->state.bo;
return (uint32_t *)batch->state.map + (offset >> 2);
}
static void *
blorp_emit_dwords(struct blorp_batch *blorp_batch, unsigned n)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return crocus_get_command_space(batch, n * sizeof(uint32_t));
}
static uint64_t
blorp_emit_reloc(struct blorp_batch *blorp_batch, UNUSED void *location,
struct blorp_address addr, uint32_t delta)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
uint32_t offset;
if (GFX_VER < 6 && crocus_ptr_in_state_buffer(batch, location)) {
offset = (char *)location - (char *)batch->state.map;
return crocus_state_reloc(batch, offset,
addr.buffer, addr.offset + delta,
addr.reloc_flags);
}
assert(!crocus_ptr_in_state_buffer(batch, location));
offset = (char *)location - (char *)batch->command.map;
return crocus_command_reloc(batch, offset,
addr.buffer, addr.offset + delta,
addr.reloc_flags);
}
static void
blorp_surface_reloc(struct blorp_batch *blorp_batch, uint32_t ss_offset,
struct blorp_address addr, uint32_t delta)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
struct crocus_bo *bo = addr.buffer;
uint64_t reloc_val =
crocus_state_reloc(batch, ss_offset, bo, addr.offset + delta,
addr.reloc_flags);
void *reloc_ptr = (void *)batch->state.map + ss_offset;
*(uint32_t *)reloc_ptr = reloc_val;
}
static uint64_t
blorp_get_surface_address(struct blorp_batch *blorp_batch,
struct blorp_address addr)
{
/* We'll let blorp_surface_reloc write the address. */
return 0ull;
}
#if GFX_VER >= 7
static struct blorp_address
blorp_get_surface_base_address(struct blorp_batch *blorp_batch)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return (struct blorp_address) {
.buffer = batch->state.bo,
.offset = 0
};
}
#endif
static void *
blorp_alloc_dynamic_state(struct blorp_batch *blorp_batch,
uint32_t size,
uint32_t alignment,
uint32_t *offset)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return stream_state(batch, size, alignment, offset, NULL);
}
UNUSED static void *
blorp_alloc_general_state(struct blorp_batch *blorp_batch,
uint32_t size,
uint32_t alignment,
uint32_t *offset)
{
/* Use dynamic state range for general state on crocus. */
return blorp_alloc_dynamic_state(blorp_batch, size, alignment, offset);
}
static bool
blorp_alloc_binding_table(struct blorp_batch *blorp_batch,
unsigned num_entries,
unsigned state_size,
unsigned state_alignment,
uint32_t *bt_offset,
uint32_t *surface_offsets,
void **surface_maps)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
uint32_t *bt_map = stream_state(batch, num_entries * sizeof(uint32_t), 32,
bt_offset, NULL);
for (unsigned i = 0; i < num_entries; i++) {
surface_maps[i] = stream_state(batch,
state_size, state_alignment,
&(surface_offsets)[i], NULL);
bt_map[i] = surface_offsets[i];
}
return true;
}
static uint32_t
blorp_binding_table_offset_to_pointer(struct blorp_batch *batch,
uint32_t offset)
{
return offset;
}
static void *
blorp_alloc_vertex_buffer(struct blorp_batch *blorp_batch,
uint32_t size,
struct blorp_address *addr)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
struct crocus_bo *bo;
uint32_t offset;
void *map = stream_state(batch, size, 64,
&offset, &bo);
*addr = (struct blorp_address) {
.buffer = bo,
.offset = offset,
.reloc_flags = RELOC_32BIT,
#if GFX_VER >= 7
.mocs = crocus_mocs(bo, &batch->screen->isl_dev),
#endif
};
return map;
}
/**
*/
static void
blorp_vf_invalidate_for_vb_48b_transitions(struct blorp_batch *blorp_batch,
const struct blorp_address *addrs,
UNUSED uint32_t *sizes,
unsigned num_vbs)
{
}
static struct blorp_address
blorp_get_workaround_address(struct blorp_batch *blorp_batch)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return (struct blorp_address) {
.buffer = batch->ice->workaround_bo,
.offset = batch->ice->workaround_offset,
};
}
static void
blorp_flush_range(UNUSED struct blorp_batch *blorp_batch,
UNUSED void *start,
UNUSED size_t size)
{
/* All allocated states come from the batch which we will flush before we
* submit it. There's nothing for us to do here.
*/
}
#if GFX_VER >= 7
static const struct intel_l3_config *
blorp_get_l3_config(struct blorp_batch *blorp_batch)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return batch->screen->l3_config_3d;
}
#endif
static void
blorp_pre_emit_urb_config(struct blorp_batch *blorp_batch,
struct intel_urb_config *urb_cfg)
{
/* Dummy. */
}
static void
blorp_emit_urb_config(struct blorp_batch *blorp_batch,
struct intel_urb_config *urb_cfg)
{
#if GFX_VER < 7
struct crocus_batch *batch = blorp_batch->driver_batch;
#if GFX_VER <= 5
batch->screen->vtbl.calculate_urb_fence(batch, 0,
urb_cfg->size[MESA_SHADER_VERTEX],
urb_cfg->size[MESA_SHADER_FRAGMENT]);
#else
genX(crocus_upload_urb)(batch, urb_cfg->size[MESA_SHADER_VERTEX], false,
urb_cfg->size[MESA_SHADER_VERTEX]);
#endif
#endif
}
static void
crocus_blorp_exec(struct blorp_batch *blorp_batch,
const struct blorp_params *params)
{
struct crocus_context *ice = blorp_batch->blorp->driver_ctx;
struct crocus_batch *batch = blorp_batch->driver_batch;
/* Flush the sampler and render caches. We definitely need to flush the
* sampler cache so that we get updated contents from the render cache for
* the glBlitFramebuffer() source. Also, we are sometimes warned in the
* docs to flush the cache between reinterpretations of the same surface
* data with different formats, which blorp does for stencil and depth
* data.
*/
if (params->src.enabled)
crocus_cache_flush_for_read(batch, params->src.addr.buffer);
if (params->dst.enabled) {
crocus_cache_flush_for_render(batch, params->dst.addr.buffer,
params->dst.view.format,
params->dst.aux_usage);
}
if (params->depth.enabled)
crocus_cache_flush_for_depth(batch, params->depth.addr.buffer);
if (params->stencil.enabled)
crocus_cache_flush_for_depth(batch, params->stencil.addr.buffer);
crocus_require_command_space(batch, 1400);
crocus_require_statebuffer_space(batch, 600);
batch->no_wrap = true;
#if GFX_VER == 8
genX(crocus_update_pma_fix)(ice, batch, false);
#endif
#if GFX_VER == 6
/* Emit workaround flushes when we switch from drawing to blorping. */
crocus_emit_post_sync_nonzero_flush(batch);
#endif
#if GFX_VER >= 6
crocus_emit_depth_stall_flushes(batch);
#endif
blorp_emit(blorp_batch, GENX(3DSTATE_DRAWING_RECTANGLE), rect) {
rect.ClippedDrawingRectangleXMax = MAX2(params->x1, params->x0) - 1;
rect.ClippedDrawingRectangleYMax = MAX2(params->y1, params->y0) - 1;
}
batch->screen->vtbl.update_surface_base_address(batch);
crocus_handle_always_flush_cache(batch);
batch->contains_draw = true;
blorp_exec(blorp_batch, params);
batch->no_wrap = false;
crocus_handle_always_flush_cache(batch);
/* We've smashed all state compared to what the normal 3D pipeline
* rendering tracks for GL.
*/
uint64_t skip_bits = (CROCUS_DIRTY_POLYGON_STIPPLE |
CROCUS_DIRTY_GEN7_SO_BUFFERS |
CROCUS_DIRTY_SO_DECL_LIST |
CROCUS_DIRTY_LINE_STIPPLE |
CROCUS_ALL_DIRTY_FOR_COMPUTE |
CROCUS_DIRTY_GEN6_SCISSOR_RECT |
CROCUS_DIRTY_GEN75_VF |
CROCUS_DIRTY_SF_CL_VIEWPORT);
uint64_t skip_stage_bits = (CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE |
CROCUS_STAGE_DIRTY_UNCOMPILED_VS |
CROCUS_STAGE_DIRTY_UNCOMPILED_TCS |
CROCUS_STAGE_DIRTY_UNCOMPILED_TES |
CROCUS_STAGE_DIRTY_UNCOMPILED_GS |
CROCUS_STAGE_DIRTY_UNCOMPILED_FS |
CROCUS_STAGE_DIRTY_SAMPLER_STATES_VS |
CROCUS_STAGE_DIRTY_SAMPLER_STATES_TCS |
CROCUS_STAGE_DIRTY_SAMPLER_STATES_TES |
CROCUS_STAGE_DIRTY_SAMPLER_STATES_GS);
if (!ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL]) {
/* BLORP disabled tessellation, that's fine for the next draw */
skip_stage_bits |= CROCUS_STAGE_DIRTY_TCS |
CROCUS_STAGE_DIRTY_TES |
CROCUS_STAGE_DIRTY_CONSTANTS_TCS |
CROCUS_STAGE_DIRTY_CONSTANTS_TES |
CROCUS_STAGE_DIRTY_BINDINGS_TCS |
CROCUS_STAGE_DIRTY_BINDINGS_TES;
}
if (!ice->shaders.uncompiled[MESA_SHADER_GEOMETRY]) {
/* BLORP disabled geometry shaders, that's fine for the next draw */
skip_stage_bits |= CROCUS_STAGE_DIRTY_GS |
CROCUS_STAGE_DIRTY_CONSTANTS_GS |
CROCUS_STAGE_DIRTY_BINDINGS_GS;
}
/* we can skip flagging CROCUS_DIRTY_DEPTH_BUFFER, if
* BLORP_BATCH_NO_EMIT_DEPTH_STENCIL is set.
*/
if (blorp_batch->flags & BLORP_BATCH_NO_EMIT_DEPTH_STENCIL)
skip_bits |= CROCUS_DIRTY_DEPTH_BUFFER;
if (!params->fs_prog_data)
skip_bits |= CROCUS_DIRTY_GEN6_BLEND_STATE;
ice->state.dirty |= ~skip_bits;
ice->state.stage_dirty |= ~skip_stage_bits;
ice->urb.vsize = 0;
ice->urb.gs_present = false;
ice->urb.gsize = 0;
ice->urb.tess_present = false;
ice->urb.hsize = 0;
ice->urb.dsize = 0;
if (params->dst.enabled) {
crocus_render_cache_add_bo(batch, params->dst.addr.buffer,
params->dst.view.format,
params->dst.aux_usage);
}
if (params->depth.enabled)
crocus_depth_cache_add_bo(batch, params->depth.addr.buffer);
if (params->stencil.enabled)
crocus_depth_cache_add_bo(batch, params->stencil.addr.buffer);
}
static void
blorp_measure_start(struct blorp_batch *blorp_batch,
const struct blorp_params *params)
{
}
static void
blorp_measure_end(struct blorp_batch *blorp_batch,
const struct blorp_params *params)
{
}
static void
blorp_emit_pre_draw(struct blorp_batch *batch, const struct blorp_params *params)
{
/* "Not implemented" */
}
static void
blorp_emit_post_draw(struct blorp_batch *batch, const struct blorp_params *params)
{
/* "Not implemented" */
}
void
genX(crocus_init_blorp)(struct crocus_context *ice)
{
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
blorp_init_elk(&ice->blorp, ice, &screen->isl_dev, screen->compiler, NULL);
ice->blorp.lookup_shader = crocus_blorp_lookup_shader;
ice->blorp.upload_shader = crocus_blorp_upload_shader;
ice->blorp.get_surface_address = blorp_get_surface_address;
ice->blorp.exec = crocus_blorp_exec;
}
+420
View File
@@ -0,0 +1,420 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/* blt command encoding for gen4/5 */
#include "crocus_context.h"
#include "crocus_genx_macros.h"
#include "crocus_genx_protos.h"
#include "crocus_resource.h"
#define FILE_DEBUG_FLAG DEBUG_BLIT
#if GFX_VER <= 5
static uint32_t
color_depth_for_cpp(int cpp)
{
switch (cpp) {
case 4: return COLOR_DEPTH_32bit;
case 2: return COLOR_DEPTH_565;
case 1: return COLOR_DEPTH_8bit;
default:
UNREACHABLE("not reached");
}
}
static void
blt_set_alpha_to_one(struct crocus_batch *batch,
struct crocus_resource *dst,
int x, int y, int width, int height)
{
const struct isl_format_layout *fmtl = isl_format_get_layout(dst->surf.format);
unsigned cpp = fmtl->bpb / 8;
uint32_t pitch = dst->surf.row_pitch_B;
if (dst->surf.tiling != ISL_TILING_LINEAR)
pitch /= 4;
/* We need to split the blit into chunks that each fit within the blitter's
* restrictions. We can't use a chunk size of 32768 because we need to
* ensure that src_tile_x + chunk_size fits. We choose 16384 because it's
* a nice round power of two, big enough that performance won't suffer, and
* small enough to guarantee everything fits.
*/
const uint32_t max_chunk_size = 16384;
for (uint32_t chunk_x = 0; chunk_x < width; chunk_x += max_chunk_size) {
for (uint32_t chunk_y = 0; chunk_y < height; chunk_y += max_chunk_size) {
const uint32_t chunk_w = MIN2(max_chunk_size, width - chunk_x);
const uint32_t chunk_h = MIN2(max_chunk_size, height - chunk_y);
uint32_t tile_x, tile_y;
uint64_t offset_B;
ASSERTED uint32_t z_offset_el, array_offset;
isl_tiling_get_intratile_offset_el(dst->surf.tiling, dst->surf.dim,
dst->surf.msaa_layout,
cpp * 8, dst->surf.samples,
dst->surf.row_pitch_B,
dst->surf.array_pitch_el_rows,
chunk_x, chunk_y, 0, 0,
&offset_B,
&tile_x, &tile_y,
&z_offset_el, &array_offset);
assert(z_offset_el == 0);
assert(array_offset == 0);
crocus_emit_cmd(batch, GENX(XY_COLOR_BLT), xyblt) {
xyblt.TilingEnable = dst->surf.tiling != ISL_TILING_LINEAR;
xyblt.ColorDepth = color_depth_for_cpp(cpp);
xyblt.RasterOperation = 0xF0;
xyblt.DestinationPitch = pitch;
xyblt._32bppByteMask = 2;
xyblt.DestinationBaseAddress = rw_bo(dst->bo, offset_B);
xyblt.DestinationX1Coordinate = tile_x;
xyblt.DestinationY1Coordinate = tile_y;
xyblt.DestinationX2Coordinate = tile_x + chunk_w;
xyblt.DestinationY2Coordinate = tile_y + chunk_h;
xyblt.SolidPatternColor = 0xffffffff;
}
}
}
}
static bool validate_blit_for_blt(struct crocus_batch *batch,
const struct pipe_blit_info *info)
{
/* If the source and destination are the same size with no mirroring,
* the rectangles are within the size of the texture and there is no
* scissor, then we can probably use the blit engine.
*/
if (info->dst.box.width != info->src.box.width ||
info->dst.box.height != info->src.box.height)
return false;
if (info->scissor_enable)
return false;
if (info->dst.box.height < 0 || info->src.box.height < 0)
return false;
if (info->dst.box.depth > 1 || info->src.box.depth > 1)
return false;
const struct util_format_description *desc =
util_format_description(info->src.format);
int i = util_format_get_first_non_void_channel(info->src.format);
if (i == -1)
return false;
/* can't do the alpha to 1 setting for these. */
if ((util_format_has_alpha1(info->src.format) &&
util_format_has_alpha(info->dst.format) &&
desc->channel[i].size > 8))
return false;
return true;
}
static inline int crocus_resource_blt_pitch(struct crocus_resource *res)
{
int pitch = res->surf.row_pitch_B;
if (res->surf.tiling != ISL_TILING_LINEAR)
pitch /= 4;
return pitch;
}
static bool emit_copy_blt(struct crocus_batch *batch,
struct crocus_resource *src,
struct crocus_resource *dst,
unsigned cpp,
int32_t src_pitch,
unsigned src_offset,
int32_t dst_pitch,
unsigned dst_offset,
uint16_t src_x, uint16_t src_y,
uint16_t dst_x, uint16_t dst_y,
uint16_t w, uint16_t h)
{
uint32_t src_tile_w, src_tile_h;
uint32_t dst_tile_w, dst_tile_h;
int dst_y2 = dst_y + h;
int dst_x2 = dst_x + w;
DBG("%s src:buf(%p)/%d+%d %d,%d dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
__func__,
src, src_pitch, src_offset, src_x, src_y,
dst, dst_pitch, dst_offset, dst_x, dst_y, w, h);
isl_get_tile_dims(src->surf.tiling, cpp, &src_tile_w, &src_tile_h);
isl_get_tile_dims(dst->surf.tiling, cpp, &dst_tile_w, &dst_tile_h);
/* For Tiled surfaces, the pitch has to be a multiple of the Tile width
* (X direction width of the Tile). This is ensured while allocating the
* buffer object.
*/
assert(src->surf.tiling == ISL_TILING_LINEAR || (src_pitch % src_tile_w) == 0);
assert(dst->surf.tiling == ISL_TILING_LINEAR || (dst_pitch % dst_tile_w) == 0);
/* For big formats (such as floating point), do the copy using 16 or
* 32bpp and multiply the coordinates.
*/
if (cpp > 4) {
if (cpp % 4 == 2) {
dst_x *= cpp / 2;
dst_x2 *= cpp / 2;
src_x *= cpp / 2;
cpp = 2;
} else {
assert(cpp % 4 == 0);
dst_x *= cpp / 4;
dst_x2 *= cpp / 4;
src_x *= cpp / 4;
cpp = 4;
}
}
/* Blit pitch must be dword-aligned. Otherwise, the hardware appears to drop
* the low bits. Offsets must be naturally aligned.
*/
if (src_pitch % 4 != 0 || src_offset % cpp != 0 ||
dst_pitch % 4 != 0 || dst_offset % cpp != 0)
return false;
/* For tiled source and destination, pitch value should be specified
* as a number of Dwords.
*/
if (dst->surf.tiling != ISL_TILING_LINEAR)
dst_pitch /= 4;
if (src->surf.tiling != ISL_TILING_LINEAR)
src_pitch /= 4;
assert(cpp <= 4);
crocus_emit_cmd(batch, GENX(XY_SRC_COPY_BLT), xyblt) {
xyblt.RasterOperation = 0xCC;
xyblt.DestinationTilingEnable = dst->surf.tiling != ISL_TILING_LINEAR;
xyblt.SourceTilingEnable = src->surf.tiling != ISL_TILING_LINEAR;
xyblt.SourceBaseAddress = ro_bo(src->bo, src_offset);
xyblt.DestinationBaseAddress = rw_bo(dst->bo, dst_offset);
xyblt.ColorDepth = color_depth_for_cpp(cpp);
xyblt._32bppByteMask = cpp == 4 ? 0x3 : 0x1;
xyblt.DestinationX1Coordinate = dst_x;
xyblt.DestinationY1Coordinate = dst_y;
xyblt.DestinationX2Coordinate = dst_x2;
xyblt.DestinationY2Coordinate = dst_y2;
xyblt.DestinationPitch = dst_pitch;
xyblt.SourceX1Coordinate = src_x;
xyblt.SourceY1Coordinate = src_y;
xyblt.SourcePitch = src_pitch;
};
crocus_emit_mi_flush(batch);
return true;
}
static bool crocus_emit_blt(struct crocus_batch *batch,
struct crocus_resource *src,
struct crocus_resource *dst,
unsigned dst_level,
unsigned dst_x, unsigned dst_y,
unsigned dst_z,
unsigned src_level,
const struct pipe_box *src_box)
{
const struct isl_format_layout *src_fmtl = isl_format_get_layout(src->surf.format);
unsigned src_cpp = src_fmtl->bpb / 8;
const struct isl_format_layout *dst_fmtl = isl_format_get_layout(dst->surf.format);
const unsigned dst_cpp = dst_fmtl->bpb / 8;
uint16_t src_x, src_y;
uint32_t src_image_x, src_image_y, dst_image_x, dst_image_y;
uint32_t src_width = src_box->width, src_height = src_box->height;
/* gen4/5 can't handle Y tiled blits. */
if (src->surf.tiling == ISL_TILING_Y0 || dst->surf.tiling == ISL_TILING_Y0)
return false;
if (src->surf.format != dst->surf.format)
return false;
if (src_cpp != dst_cpp)
return false;
src_x = src_box->x;
src_y = src_box->y;
assert(src_cpp == dst_cpp);
crocus_resource_get_image_offset(src, src_level, src_box->z, &src_image_x,
&src_image_y);
if (util_format_is_compressed(src->base.b.format)) {
int bw = util_format_get_blockwidth(src->base.b.format);
int bh = util_format_get_blockheight(src->base.b.format);
assert(src_x % bw == 0);
assert(src_y % bh == 0);
src_x /= (int)bw;
src_y /= (int)bh;
src_width = DIV_ROUND_UP(src_width, (int)bw);
src_height = DIV_ROUND_UP(src_height, (int)bh);
}
crocus_resource_get_image_offset(dst, dst_level, dst_z, &dst_image_x,
&dst_image_y);
if (util_format_is_compressed(dst->base.b.format)) {
int bw = util_format_get_blockwidth(dst->base.b.format);
int bh = util_format_get_blockheight(dst->base.b.format);
assert(dst_x % bw == 0);
assert(dst_y % bh == 0);
dst_x /= (int)bw;
dst_y /= (int)bh;
}
src_x += src_image_x;
src_y += src_image_y;
dst_x += dst_image_x;
dst_y += dst_image_y;
/* According to the Ivy Bridge PRM, Vol1 Part4, section 1.2.1.2 (Graphics
* Data Size Limitations):
*
* The BLT engine is capable of transferring very large quantities of
* graphics data. Any graphics data read from and written to the
* destination is permitted to represent a number of pixels that
* occupies up to 65,536 scan lines and up to 32,768 bytes per scan line
* at the destination. The maximum number of pixels that may be
* represented per scan line’s worth of graphics data depends on the
* color depth.
*
* The blitter's pitch is a signed 16-bit integer, but measured in bytes
* for linear surfaces and DWords for tiled surfaces. So the maximum
* pitch is 32k linear and 128k tiled.
*/
if (crocus_resource_blt_pitch(src) >= 32768 ||
crocus_resource_blt_pitch(dst) >= 32768) {
return false;
}
/* We need to split the blit into chunks that each fit within the blitter's
* restrictions. We can't use a chunk size of 32768 because we need to
* ensure that src_tile_x + chunk_size fits. We choose 16384 because it's
* a nice round power of two, big enough that performance won't suffer, and
* small enough to guarantee everything fits.
*/
const uint32_t max_chunk_size = 16384;
for (uint32_t chunk_x = 0; chunk_x < src_width; chunk_x += max_chunk_size) {
for (uint32_t chunk_y = 0; chunk_y < src_height; chunk_y += max_chunk_size) {
const uint32_t chunk_w = MIN2(max_chunk_size, src_width - chunk_x);
const uint32_t chunk_h = MIN2(max_chunk_size, src_height - chunk_y);
uint64_t src_offset;
uint32_t src_tile_x, src_tile_y;
ASSERTED uint32_t z_offset_el, array_offset;
isl_tiling_get_intratile_offset_el(src->surf.tiling, src->surf.dim,
src->surf.msaa_layout,
src_cpp * 8, src->surf.samples,
src->surf.row_pitch_B,
src->surf.array_pitch_el_rows,
src_x + chunk_x, src_y + chunk_y, 0, 0,
&src_offset,
&src_tile_x, &src_tile_y,
&z_offset_el, &array_offset);
assert(z_offset_el == 0);
assert(array_offset == 0);
uint64_t dst_offset;
uint32_t dst_tile_x, dst_tile_y;
isl_tiling_get_intratile_offset_el(dst->surf.tiling, dst->surf.dim,
dst->surf.msaa_layout,
dst_cpp * 8, dst->surf.samples,
dst->surf.row_pitch_B,
dst->surf.array_pitch_el_rows,
dst_x + chunk_x, dst_y + chunk_y, 0, 0,
&dst_offset,
&dst_tile_x, &dst_tile_y,
&z_offset_el, &array_offset);
assert(z_offset_el == 0);
assert(array_offset == 0);
if (!emit_copy_blt(batch, src, dst,
src_cpp, src->surf.row_pitch_B,
src_offset,
dst->surf.row_pitch_B, dst_offset,
src_tile_x, src_tile_y,
dst_tile_x, dst_tile_y,
chunk_w, chunk_h)) {
return false;
}
}
}
if (util_format_has_alpha1(src->base.b.format) &&
util_format_has_alpha(dst->base.b.format))
blt_set_alpha_to_one(batch, dst, 0, 0, src_width, src_height);
return true;
}
static bool crocus_blit_blt(struct crocus_batch *batch,
const struct pipe_blit_info *info)
{
if (!validate_blit_for_blt(batch, info))
return false;
return crocus_emit_blt(batch,
(struct crocus_resource *)info->src.resource,
(struct crocus_resource *)info->dst.resource,
info->dst.level,
info->dst.box.x,
info->dst.box.y,
info->dst.box.z,
info->src.level,
&info->src.box);
}
static bool crocus_copy_region_blt(struct crocus_batch *batch,
struct crocus_resource *dst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct crocus_resource *src,
unsigned src_level,
const struct pipe_box *src_box)
{
if (dst->base.b.target == PIPE_BUFFER || src->base.b.target == PIPE_BUFFER)
return false;
return crocus_emit_blt(batch,
src,
dst,
dst_level,
dstx, dsty, dstz,
src_level,
src_box);
}
#endif
void
genX(crocus_init_blt)(struct crocus_screen *screen)
{
#if GFX_VER <= 5
screen->vtbl.blit_blt = crocus_blit_blt;
screen->vtbl.copy_region_blt = crocus_copy_region_blt;
#else
screen->vtbl.blit_blt = NULL;
screen->vtbl.copy_region_blt = NULL;
#endif
}
File diff suppressed because it is too large. Load diff
+356
View File
@@ -0,0 +1,356 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef CROCUS_BUFMGR_H
#define CROCUS_BUFMGR_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include "util/macros.h"
#include "util/u_atomic.h"
#include "util/list.h"
#include "pipe/p_defines.h"
struct crocus_batch;
struct intel_device_info;
struct util_debug_callback;
#define CROCUS_BINDER_SIZE (64 * 1024)
#define CROCUS_MAX_BINDERS 100
struct crocus_bo {
/**
* Size in bytes of the buffer object.
*
* The size may be larger than the size originally requested for the
* allocation, such as being aligned to page size.
*/
uint64_t size;
/** Buffer manager context associated with this buffer object */
struct crocus_bufmgr *bufmgr;
/** The GEM handle for this buffer object. */
uint32_t gem_handle;
/**
* Virtual address of the buffer inside the PPGTT (Per-Process Graphics
* Translation Table).
*
* Although each hardware context has its own VMA, we assign BO's to the
* same address in all contexts, for simplicity.
*/
uint64_t gtt_offset;
/**
* The validation list index for this buffer, or -1 when not in a batch.
* Note that a single buffer may be in multiple batches (contexts), and
* this is a global field, which refers to the last batch using the BO.
* It should not be considered authoritative, but can be used to avoid a
* linear walk of the validation list in the common case by guessing that
* exec_bos[bo->index] == bo and confirming whether that's the case.
*
* XXX: this is not ideal now that we have more than one batch per context,
* XXX: as the index will flop back and forth between the render index and
* XXX: compute index...
*/
unsigned index;
/**
* Boolean of whether the GPU is definitely not accessing the buffer.
*
* This is only valid when reusable, since non-reusable
* buffers are those that have been shared with other
* processes, so we don't know their state.
*/
bool idle;
int refcount;
const char *name;
uint64_t kflags;
/**
* Kenel-assigned global name for this object
*
* List contains both flink named and prime fd'd objects
*/
unsigned global_name;
/**
* Current tiling mode
*/
uint32_t tiling_mode;
uint32_t swizzle_mode;
uint32_t stride;
time_t free_time;
/** Mapped address for the buffer, saved across map/unmap cycles */
void *map_cpu;
/** GTT virtual address for the buffer, saved across map/unmap cycles */
void *map_gtt;
/** WC CPU address for the buffer, saved across map/unmap cycles */
void *map_wc;
/** BO cache list */
struct list_head head;
/** List of GEM handle exports of this buffer (bo_export) */
struct list_head exports;
/**
* Boolean of whether this buffer can be re-used
*/
bool reusable;
/**
* Boolean of whether this buffer has been shared with an external client.
*/
bool external;
/**
* Boolean of whether this buffer is cache coherent
*/
bool cache_coherent;
/**
* Boolean of whether this buffer points into user memory
*/
bool userptr;
/**
* Boolean of if this is used for scanout.
*/
bool scanout;
/** Pre-computed hash using _mesa_hash_pointer for cache tracking sets */
uint32_t hash;
};
#define BO_ALLOC_ZEROED (1 << 0)
#define BO_ALLOC_COHERENT (1 << 1)
#define BO_ALLOC_SCANOUT (1 << 2)
/**
* Allocate a buffer object.
*
* Buffer objects are not necessarily initially mapped into CPU virtual
* address space or graphics device aperture. They must be mapped
* using crocus_bo_map() to be used by the CPU.
*/
struct crocus_bo *crocus_bo_alloc(struct crocus_bufmgr *bufmgr,
const char *name, uint64_t size);
/**
* Allocate a tiled buffer object.
*
* Alignment for tiled objects is set automatically; the 'flags'
* argument provides a hint about how the object will be used initially.
*
* Valid tiling formats are:
* I915_TILING_NONE
* I915_TILING_X
* I915_TILING_Y
*/
struct crocus_bo *crocus_bo_alloc_tiled(struct crocus_bufmgr *bufmgr,
const char *name, uint64_t size,
uint32_t alignment,
uint32_t tiling_mode, uint32_t pitch,
unsigned flags);
struct crocus_bo *crocus_bo_create_userptr(struct crocus_bufmgr *bufmgr,
const char *name, void *ptr,
size_t size);
/** Takes a reference on a buffer object */
static inline void
crocus_bo_reference(struct crocus_bo *bo)
{
p_atomic_inc(&bo->refcount);
}
static inline int
atomic_add_unless(int *v, int add, int unless)
{
int c, old;
c = p_atomic_read(v);
while (c != unless && (old = p_atomic_cmpxchg(v, c, c + add)) != c)
c = old;
return c == unless;
}
void __crocus_bo_unreference(struct crocus_bo *bo);
/**
* Releases a reference on a buffer object, freeing the data if
* no references remain.
*/
static inline void crocus_bo_unreference(struct crocus_bo *bo)
{
if (bo == NULL)
return;
assert(p_atomic_read(&bo->refcount) > 0);
if (atomic_add_unless(&bo->refcount, -1, 1)) {
__crocus_bo_unreference(bo);
}
}
#define MAP_READ PIPE_MAP_READ
#define MAP_WRITE PIPE_MAP_WRITE
#define MAP_ASYNC PIPE_MAP_UNSYNCHRONIZED
#define MAP_PERSISTENT PIPE_MAP_PERSISTENT
#define MAP_COHERENT PIPE_MAP_COHERENT
/* internal */
#define MAP_INTERNAL_MASK (0xff << 24)
#define MAP_RAW (0x01 << 24)
#define MAP_FLAGS (MAP_READ | MAP_WRITE | MAP_ASYNC | \
MAP_PERSISTENT | MAP_COHERENT | MAP_INTERNAL_MASK)
/**
* Maps the buffer into userspace.
*
* This function will block waiting for any existing execution on the
* buffer to complete, first. The resulting mapping is returned.
*/
MUST_CHECK void *crocus_bo_map(struct util_debug_callback *dbg,
struct crocus_bo *bo, unsigned flags);
/**
* Reduces the refcount on the userspace mapping of the buffer
* object.
*/
static inline int crocus_bo_unmap(struct crocus_bo *bo) { return 0; }
/**
* Waits for rendering to an object by the GPU to have completed.
*
* This is not required for any access to the BO by bo_map,
* bo_subdata, etc. It is merely a way for the driver to implement
* glFinish.
*/
void crocus_bo_wait_rendering(struct crocus_bo *bo);
/**
* Unref a buffer manager instance.
*/
void crocus_bufmgr_unref(struct crocus_bufmgr *bufmgr);
/**
* Get the current tiling (and resulting swizzling) mode for the bo.
*
* \param buf Buffer to get tiling mode for
* \param tiling_mode returned tiling mode
* \param swizzle_mode returned swizzling mode
*/
int crocus_bo_get_tiling(struct crocus_bo *bo, uint32_t *tiling_mode,
uint32_t *swizzle_mode);
/**
* Create a visible name for a buffer which can be used by other apps
*
* \param buf Buffer to create a name for
* \param name Returned name
*/
int crocus_bo_flink(struct crocus_bo *bo, uint32_t *name);
/**
* Is this buffer shared with external clients (exported)?
*/
static inline bool
crocus_bo_is_external(const struct crocus_bo *bo)
{
return bo->external;
}
/**
* Returns 1 if mapping the buffer for write could cause the process
* to block, due to the object being active in the GPU.
*/
int crocus_bo_busy(struct crocus_bo *bo);
/**
* Specify the volatility of the buffer.
* \param bo Buffer to create a name for
* \param madv The purgeable status
*
* Use I915_MADV_DONTNEED to mark the buffer as purgeable, and it will be
* reclaimed under memory pressure. If you subsequently require the buffer,
* then you must pass I915_MADV_WILLNEED to mark the buffer as required.
*
* Returns 1 if the buffer was retained, or 0 if it was discarded whilst
* marked as I915_MADV_DONTNEED.
*/
int crocus_bo_madvise(struct crocus_bo *bo, int madv);
struct crocus_bufmgr *
crocus_bufmgr_get_for_fd(struct intel_device_info *devinfo, int fd,
bool bo_reuse);
int crocus_bufmgr_get_fd(struct crocus_bufmgr *bufmgr);
struct crocus_bo *crocus_bo_gem_create_from_name(struct crocus_bufmgr *bufmgr,
const char *name,
unsigned handle);
int crocus_bo_wait(struct crocus_bo *bo, int64_t timeout_ns);
uint32_t crocus_create_hw_context(struct crocus_bufmgr *bufmgr);
uint32_t crocus_clone_hw_context(struct crocus_bufmgr *bufmgr, uint32_t ctx_id);
#define CROCUS_CONTEXT_LOW_PRIORITY ((I915_CONTEXT_MIN_USER_PRIORITY - 1) / 2)
#define CROCUS_CONTEXT_MEDIUM_PRIORITY (I915_CONTEXT_DEFAULT_PRIORITY)
#define CROCUS_CONTEXT_HIGH_PRIORITY ((I915_CONTEXT_MAX_USER_PRIORITY + 1) / 2)
int crocus_hw_context_set_priority(struct crocus_bufmgr *bufmgr,
uint32_t ctx_id, int priority);
void crocus_destroy_hw_context(struct crocus_bufmgr *bufmgr, uint32_t ctx_id);
int crocus_bo_export_dmabuf(struct crocus_bo *bo, int *prime_fd);
struct crocus_bo *crocus_bo_import_dmabuf(struct crocus_bufmgr *bufmgr,
int prime_fd, uint64_t modifier);
struct crocus_bo *crocus_bo_import_dmabuf_no_mods(struct crocus_bufmgr *bufmgr,
int prime_fd);
/**
* Exports a bo as a GEM handle into a given DRM file descriptor
* \param bo Buffer to export
* \param drm_fd File descriptor where the new handle is created
* \param out_handle Pointer to store the new handle
*
* Returns 0 if the buffer was successfully exported, a non zero error code
* otherwise.
*/
int crocus_bo_export_gem_handle_for_device(struct crocus_bo *bo, int drm_fd,
uint32_t *out_handle);
uint32_t crocus_bo_export_gem_handle(struct crocus_bo *bo);
int drm_ioctl(int fd, unsigned long request, void *arg);
#endif /* CROCUS_BUFMGR_H */
+829
View File
@@ -0,0 +1,829 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <errno.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/u_inlines.h"
#include "util/u_surface.h"
#include "util/format/u_format.h"
#include "util/u_upload_mgr.h"
#include "util/ralloc.h"
#include "crocus_context.h"
#include "crocus_resource.h"
#include "crocus_screen.h"
#include "intel/compiler/elk/elk_compiler.h"
#include "util/format_srgb.h"
static bool
crocus_is_color_fast_clear_compatible(struct crocus_context *ice,
enum isl_format format,
const union isl_color_value color)
{
if (isl_format_has_int_channel(format)) {
perf_debug(&ice->dbg, "Integer fast clear not enabled for %s",
isl_format_get_name(format));
return false;
}
for (int i = 0; i < 4; i++) {
if (!isl_format_has_color_component(format, i)) {
continue;
}
if (color.f32[i] != 0.0f && color.f32[i] != 1.0f) {
return false;
}
}
return true;
}
static bool
can_fast_clear_color(struct crocus_context *ice,
struct pipe_resource *p_res,
unsigned level,
const struct pipe_box *box,
bool render_condition_enabled,
enum isl_format format,
enum isl_format render_format,
union isl_color_value color)
{
struct crocus_resource *res = (void *) p_res;
if (INTEL_DEBUG(DEBUG_NO_FAST_CLEAR))
return false;
if (!isl_aux_usage_has_fast_clears(res->aux.usage))
return false;
/* Check for partial clear */
if (box->x > 0 || box->y > 0 ||
box->width < u_minify(p_res->width0, level) ||
box->height < u_minify(p_res->height0, level)) {
return false;
}
/* Avoid conditional fast clears to maintain correct tracking of the aux
* state (see iris_resource_finish_write for more info). Note that partial
* fast clears (if they existed) would not pose a problem with conditional
* rendering.
*/
if (render_condition_enabled &&
ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
return false;
}
/* We store clear colors as floats or uints as needed. If there are
* texture views in play, the formats will not properly be respected
* during resolves because the resolve operations only know about the
* resource and not the renderbuffer.
*/
if (!crocus_render_formats_color_compatible(render_format, res->surf.format,
color)) {
return false;
}
/* XXX: if (irb->mt->supports_fast_clear)
* see intel_miptree_create_for_dri_image()
*/
if (!crocus_is_color_fast_clear_compatible(ice, format, color))
return false;
return true;
}
static union isl_color_value
convert_fast_clear_color(struct crocus_context *ice,
struct crocus_resource *res,
enum isl_format render_format,
const union isl_color_value color)
{
union isl_color_value override_color = color;
struct pipe_resource *p_res = (void *) res;
const enum pipe_format format = p_res->format;
const struct util_format_description *desc =
util_format_description(format);
unsigned colormask = util_format_colormask(desc);
if (util_format_is_intensity(format) ||
util_format_is_luminance(format) ||
util_format_is_luminance_alpha(format)) {
override_color.u32[1] = override_color.u32[0];
override_color.u32[2] = override_color.u32[0];
if (util_format_is_intensity(format))
override_color.u32[3] = override_color.u32[0];
} else {
for (int chan = 0; chan < 3; chan++) {
if (!(colormask & (1 << chan)))
override_color.u32[chan] = 0;
}
}
if (util_format_is_unorm(format)) {
for (int i = 0; i < 4; i++)
override_color.f32[i] = CLAMP(override_color.f32[i], 0.0f, 1.0f);
} else if (util_format_is_snorm(format)) {
for (int i = 0; i < 4; i++)
override_color.f32[i] = CLAMP(override_color.f32[i], -1.0f, 1.0f);
} else if (util_format_is_pure_uint(format)) {
for (int i = 0; i < 4; i++) {
unsigned bits = util_format_get_component_bits(
format, UTIL_FORMAT_COLORSPACE_RGB, i);
if (bits < 32) {
uint32_t max = (1u << bits) - 1;
override_color.u32[i] = MIN2(override_color.u32[i], max);
}
}
} else if (util_format_is_pure_sint(format)) {
for (int i = 0; i < 4; i++) {
unsigned bits = util_format_get_component_bits(
format, UTIL_FORMAT_COLORSPACE_RGB, i);
if (bits < 32) {
int32_t max = (1 << (bits - 1)) - 1;
int32_t min = -(1 << (bits - 1));
override_color.i32[i] = CLAMP(override_color.i32[i], min, max);
}
}
} else if (format == PIPE_FORMAT_R11G11B10_FLOAT ||
format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
/* these packed float formats only store unsigned values */
for (int i = 0; i < 4; i++)
override_color.f32[i] = MAX2(override_color.f32[i], 0.0f);
}
if (!(colormask & 1 << 3)) {
if (util_format_is_pure_integer(format))
override_color.u32[3] = 1;
else
override_color.f32[3] = 1.0f;
}
/* Handle linear to SRGB conversion */
if (isl_format_is_srgb(render_format)) {
for (int i = 0; i < 3; i++) {
override_color.f32[i] =
util_format_linear_to_srgb_float(override_color.f32[i]);
}
}
return override_color;
}
static void
fast_clear_color(struct crocus_context *ice,
struct crocus_resource *res,
unsigned level,
const struct pipe_box *box,
enum isl_format format,
union isl_color_value color,
enum blorp_batch_flags blorp_flags)
{
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_screen *screen = batch->screen;
struct pipe_resource *p_res = (void *) res;
color = convert_fast_clear_color(ice, res, format, color);
bool color_changed = !!memcmp(&res->aux.clear_color, &color,
sizeof(color));
if (color_changed) {
/* If we are clearing to a new clear value, we need to resolve fast
* clears from other levels/layers first, since we can't have different
* levels/layers with different fast clear colors.
*/
for (unsigned res_lvl = 0; res_lvl < res->surf.levels; res_lvl++) {
const unsigned level_layers =
crocus_get_num_logical_layers(res, res_lvl);
for (unsigned layer = 0; layer < level_layers; layer++) {
if (res_lvl == level &&
layer >= box->z &&
layer < box->z + box->depth) {
/* We're going to clear this layer anyway. Leave it alone. */
continue;
}
enum isl_aux_state aux_state =
crocus_resource_get_aux_state(res, res_lvl, layer);
if (aux_state != ISL_AUX_STATE_CLEAR &&
aux_state != ISL_AUX_STATE_PARTIAL_CLEAR &&
aux_state != ISL_AUX_STATE_COMPRESSED_CLEAR) {
/* This slice doesn't have any fast-cleared bits. */
continue;
}
/* If we got here, then the level may have fast-clear bits that use
* the old clear value. We need to do a color resolve to get rid
* of their use of the clear color before we can change it.
* Fortunately, few applications ever change their clear color at
* different levels/layers, so this shouldn't happen often.
*/
crocus_resource_prepare_access(ice, res,
res_lvl, 1, layer, 1,
res->aux.usage,
false);
perf_debug(&ice->dbg,
"Resolving resource (%p) level %d, layer %d: color changing from "
"(%0.2f, %0.2f, %0.2f, %0.2f) to "
"(%0.2f, %0.2f, %0.2f, %0.2f)\n",
res, res_lvl, layer,
res->aux.clear_color.f32[0],
res->aux.clear_color.f32[1],
res->aux.clear_color.f32[2],
res->aux.clear_color.f32[3],
color.f32[0], color.f32[1], color.f32[2], color.f32[3]);
}
}
}
crocus_resource_set_clear_color(ice, res, color);
/* If the buffer is already in ISL_AUX_STATE_CLEAR, and the color hasn't
* changed, the clear is redundant and can be skipped.
*/
const enum isl_aux_state aux_state =
crocus_resource_get_aux_state(res, level, box->z);
if (!color_changed && box->depth == 1 && aux_state == ISL_AUX_STATE_CLEAR)
return;
/* Ivybrigde PRM Vol 2, Part 1, "11.7 MCS Buffer for Render Target(s)":
*
* "Any transition from any value in {Clear, Render, Resolve} to a
* different value in {Clear, Render, Resolve} requires end of pipe
* synchronization."
*
* In other words, fast clear ops are not properly synchronized with
* other drawing. We need to use a PIPE_CONTROL to ensure that the
* contents of the previous draw hit the render target before we resolve
* and again afterwards to ensure that the resolve is complete before we
* do any more regular drawing.
*/
crocus_emit_end_of_pipe_sync(batch,
"fast clear: pre-flush",
PIPE_CONTROL_RENDER_TARGET_FLUSH);
struct blorp_batch blorp_batch;
blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags);
struct blorp_surf surf;
crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev, &surf,
p_res, res->aux.usage, level, true);
/* In newer gens (> 9), the hardware will do a linear -> sRGB conversion of
* the clear color during the fast clear, if the surface format is of sRGB
* type. We use the linear version of the surface format here to prevent
* that from happening, since we already do our own linear -> sRGB
* conversion in convert_fast_clear_color().
*/
blorp_fast_clear(&blorp_batch, &surf, isl_format_srgb_to_linear(format),
ISL_SWIZZLE_IDENTITY,
level, box->z, box->depth,
box->x, box->y, box->x + box->width,
box->y + box->height);
blorp_batch_finish(&blorp_batch);
crocus_emit_end_of_pipe_sync(batch,
"fast clear: post flush",
PIPE_CONTROL_RENDER_TARGET_FLUSH);
crocus_resource_set_aux_state(ice, res, level, box->z,
box->depth, ISL_AUX_STATE_CLEAR);
ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_BINDINGS;
return;
}
static void
clear_color(struct crocus_context *ice,
struct pipe_resource *p_res,
unsigned level,
const struct pipe_box *box,
bool render_condition_enabled,
enum isl_format format,
struct isl_swizzle swizzle,
union isl_color_value color)
{
struct crocus_resource *res = (void *) p_res;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_screen *screen = batch->screen;
const struct intel_device_info *devinfo = &batch->screen->devinfo;
enum blorp_batch_flags blorp_flags = 0;
if (render_condition_enabled) {
if (!crocus_check_conditional_render(ice))
return;
if (ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT)
blorp_flags |= BLORP_BATCH_PREDICATE_ENABLE;
}
if (p_res->target == PIPE_BUFFER)
util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width);
crocus_batch_maybe_flush(batch, 1500);
bool can_fast_clear = can_fast_clear_color(ice, p_res, level, box,
render_condition_enabled,
res->surf.format, format, color);
if (can_fast_clear) {
fast_clear_color(ice, res, level, box, format, color,
blorp_flags);
return;
}
enum isl_aux_usage aux_usage =
crocus_resource_render_aux_usage(ice, res, level, format, false);
crocus_resource_prepare_render(ice, res, level,
box->z, box->depth, aux_usage);
struct blorp_surf surf;
crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev, &surf,
p_res, aux_usage, level, true);
struct blorp_batch blorp_batch;
blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags);
if (!isl_format_supports_rendering(devinfo, format) &&
isl_format_is_rgbx(format))
format = isl_format_rgbx_to_rgba(format);
blorp_clear(&blorp_batch, &surf, format, swizzle,
level, box->z, box->depth, box->x, box->y,
box->x + box->width, box->y + box->height,
color, 0 /* color_write_disable */);
blorp_batch_finish(&blorp_batch);
crocus_flush_and_dirty_for_history(ice, batch, res,
PIPE_CONTROL_RENDER_TARGET_FLUSH,
"cache history: post color clear");
crocus_resource_finish_render(ice, res, level,
box->z, box->depth, aux_usage);
}
static bool
can_fast_clear_depth(struct crocus_context *ice,
struct crocus_resource *res,
unsigned level,
const struct pipe_box *box,
bool render_condition_enabled,
float depth)
{
struct pipe_resource *p_res = (void *) res;
struct pipe_context *ctx = (void *) ice;
struct crocus_screen *screen = (void *) ctx->screen;
const struct intel_device_info *devinfo = &screen->devinfo;
if (devinfo->ver < 6)
return false;
if (INTEL_DEBUG(DEBUG_NO_FAST_CLEAR))
return false;
/* Check for partial clears */
if (box->x > 0 || box->y > 0 ||
box->width < u_minify(p_res->width0, level) ||
box->height < u_minify(p_res->height0, level)) {
return false;
}
/* Avoid conditional fast clears to maintain correct tracking of the aux
* state (see iris_resource_finish_write for more info). Note that partial
* fast clears would not pose a problem with conditional rendering.
*/
if (render_condition_enabled &&
ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
return false;
}
if (!crocus_resource_level_has_hiz(res, level))
return false;
if (res->base.b.format == PIPE_FORMAT_Z16_UNORM) {
/* From the Sandy Bridge PRM, volume 2 part 1, page 314:
*
* "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be
* enabled (the legacy method of clearing must be performed):
*
* - DevSNB{W/A}]: When depth buffer format is D16_UNORM and the
* width of the map (LOD0) is not multiple of 16, fast clear
* optimization must be disabled.
*/
if (devinfo->ver == 6 &&
(u_minify(res->surf.phys_level0_sa.width,
level) % 16) != 0)
return false;
}
return true;
}
static void
fast_clear_depth(struct crocus_context *ice,
struct crocus_resource *res,
unsigned level,
const struct pipe_box *box,
float depth)
{
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
/* If we're clearing to a new clear value, then we need to resolve any clear
* flags out of the HiZ buffer into the real depth buffer.
*/
if (res->aux.clear_color.f32[0] != depth) {
for (unsigned res_level = 0; res_level < res->surf.levels; res_level++) {
if (!crocus_resource_level_has_hiz(res, res_level))
continue;
const unsigned level_layers =
crocus_get_num_logical_layers(res, res_level);
for (unsigned layer = 0; layer < level_layers; layer++) {
if (res_level == level &&
layer >= box->z &&
layer < box->z + box->depth) {
/* We're going to clear this layer anyway. Leave it alone. */
continue;
}
enum isl_aux_state aux_state =
crocus_resource_get_aux_state(res, res_level, layer);
if (aux_state != ISL_AUX_STATE_CLEAR &&
aux_state != ISL_AUX_STATE_COMPRESSED_CLEAR) {
/* This slice doesn't have any fast-cleared bits. */
continue;
}
/* If we got here, then the level may have fast-clear bits that
* use the old clear value. We need to do a depth resolve to get
* rid of their use of the clear value before we can change it.
* Fortunately, few applications ever change their depth clear
* value so this shouldn't happen often.
*/
crocus_hiz_exec(ice, batch, res, res_level, layer, 1,
ISL_AUX_OP_FULL_RESOLVE);
crocus_resource_set_aux_state(ice, res, res_level, layer, 1,
ISL_AUX_STATE_RESOLVED);
}
}
const union isl_color_value clear_value = { .f32 = {depth, } };
crocus_resource_set_clear_color(ice, res, clear_value);
}
for (unsigned l = 0; l < box->depth; l++) {
enum isl_aux_state aux_state =
crocus_resource_level_has_hiz(res, level) ?
crocus_resource_get_aux_state(res, level, box->z + l) :
ISL_AUX_STATE_AUX_INVALID;
if (aux_state != ISL_AUX_STATE_CLEAR) {
crocus_hiz_exec(ice, batch, res, level,
box->z + l, 1, ISL_AUX_OP_FAST_CLEAR);
}
}
crocus_resource_set_aux_state(ice, res, level, box->z, box->depth,
ISL_AUX_STATE_CLEAR);
ice->state.dirty |= CROCUS_DIRTY_DEPTH_BUFFER;
}
static void
clear_depth_stencil(struct crocus_context *ice,
struct pipe_resource *p_res,
unsigned level,
const struct pipe_box *box,
bool render_condition_enabled,
bool clear_depth,
bool clear_stencil,
float depth,
uint8_t stencil)
{
struct crocus_resource *res = (void *) p_res;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_screen *screen = batch->screen;
enum blorp_batch_flags blorp_flags = 0;
if (render_condition_enabled) {
if (!crocus_check_conditional_render(ice))
return;
if (ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT)
blorp_flags |= BLORP_BATCH_PREDICATE_ENABLE;
}
crocus_batch_maybe_flush(batch, 1500);
struct crocus_resource *z_res;
struct crocus_resource *stencil_res;
struct blorp_surf z_surf;
struct blorp_surf stencil_surf;
crocus_get_depth_stencil_resources(&batch->screen->devinfo, p_res, &z_res, &stencil_res);
if (z_res && clear_depth &&
can_fast_clear_depth(ice, z_res, level, box, render_condition_enabled,
depth)) {
fast_clear_depth(ice, z_res, level, box, depth);
crocus_flush_and_dirty_for_history(ice, batch, res, 0,
"cache history: post fast Z clear");
clear_depth = false;
z_res = NULL;
}
/* At this point, we might have fast cleared the depth buffer. So if there's
* no stencil clear pending, return early.
*/
if (!(clear_depth || (clear_stencil && stencil_res))) {
return;
}
if (clear_depth && z_res) {
const enum isl_aux_usage aux_usage =
crocus_resource_render_aux_usage(ice, z_res, level, z_res->surf.format,
false);
crocus_resource_prepare_render(ice, z_res, level, box->z, box->depth,
aux_usage);
crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev,
&z_surf, &z_res->base.b, aux_usage,
level, true);
}
struct blorp_batch blorp_batch;
blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags);
uint8_t stencil_mask = clear_stencil && stencil_res ? 0xff : 0;
if (stencil_mask) {
crocus_resource_prepare_access(ice, stencil_res, level, 1, box->z,
box->depth, stencil_res->aux.usage, false);
crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev,
&stencil_surf, &stencil_res->base.b,
stencil_res->aux.usage, level, true);
}
blorp_clear_depth_stencil(&blorp_batch, &z_surf, &stencil_surf,
level, box->z, box->depth,
box->x, box->y,
box->x + box->width,
box->y + box->height,
clear_depth && z_res, depth,
stencil_mask, stencil);
blorp_batch_finish(&blorp_batch);
crocus_flush_and_dirty_for_history(ice, batch, res, 0,
"cache history: post slow ZS clear");
if (clear_depth && z_res) {
crocus_resource_finish_render(ice, z_res, level,
box->z, box->depth, z_surf.aux_usage);
}
if (stencil_mask) {
crocus_resource_finish_write(ice, stencil_res, level, box->z, box->depth,
stencil_res->aux.usage);
}
}
/**
* The pipe->clear() driver hook.
*
* This clears buffers attached to the current draw framebuffer.
*/
static void
crocus_clear(struct pipe_context *ctx,
unsigned buffers,
uint32_t color_clear_mask,
uint8_t stencil_clear_mask,
const struct pipe_scissor_state *scissor_state,
const union pipe_color_union *p_color,
double depth,
unsigned stencil)
{
struct crocus_context *ice = (void *) ctx;
struct pipe_framebuffer_state *cso_fb = &ice->state.framebuffer;
struct crocus_screen *screen = (void *) ctx->screen;
const struct intel_device_info *devinfo = &screen->devinfo;
assert(buffers != 0);
struct pipe_box box = {
.width = cso_fb->width,
.height = cso_fb->height,
};
if (scissor_state) {
box.x = scissor_state->minx;
box.y = scissor_state->miny;
box.width = MIN2(box.width, scissor_state->maxx - scissor_state->minx);
box.height = MIN2(box.height, scissor_state->maxy - scissor_state->miny);
}
if (buffers & PIPE_CLEAR_DEPTHSTENCIL) {
if (devinfo->ver < 6) {
crocus_blitter_begin(ice, CROCUS_SAVE_FRAGMENT_STATE, true);
util_blitter_clear(ice->blitter, cso_fb->width, cso_fb->height,
util_framebuffer_get_num_layers(cso_fb),
buffers & PIPE_CLEAR_DEPTHSTENCIL, p_color, depth, stencil, false);
} else {
const struct pipe_surface *psurf = &cso_fb->zsbuf;
box.depth = psurf->last_layer - psurf->first_layer + 1;
box.z = psurf->first_layer;
clear_depth_stencil(ice, psurf->texture, psurf->level, &box, true,
buffers & PIPE_CLEAR_DEPTH,
buffers & PIPE_CLEAR_STENCIL,
depth, stencil);
}
buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
}
if (buffers & PIPE_CLEAR_COLOR) {
/* pipe_color_union and isl_color_value are interchangeable */
union isl_color_value *color = (void *) p_color;
for (unsigned i = 0; i < cso_fb->nr_cbufs; i++) {
if (buffers & (PIPE_CLEAR_COLOR0 << i)) {
struct pipe_surface *psurf = ice->state.fb_cbufs[i];
struct crocus_surface *isurf = (void *) psurf;
box.depth = psurf->last_layer - psurf->first_layer + 1,
box.z = psurf->first_layer,
clear_color(ice, psurf->texture, psurf->level, &box,
true, isurf->view.format, isurf->view.swizzle,
*color);
}
}
}
}
/**
* The pipe->clear_texture() driver hook.
*
* This clears the given texture resource.
*/
static void
crocus_clear_texture(struct pipe_context *ctx,
struct pipe_resource *p_res,
unsigned level,
const struct pipe_box *box,
const void *data)
{
struct crocus_context *ice = (void *) ctx;
struct crocus_screen *screen = (void *) ctx->screen;
const struct intel_device_info *devinfo = &screen->devinfo;
if (devinfo->ver < 6) {
u_default_clear_texture(ctx, p_res, level, box, data);
return;
}
if (util_format_is_depth_or_stencil(p_res->format)) {
const struct util_format_unpack_description *fmt_unpack =
util_format_unpack_description(p_res->format);
float depth = 0.0;
uint8_t stencil = 0;
if (fmt_unpack->unpack_z_float)
fmt_unpack->unpack_z_float(&depth, 0, data, 0, 1, 1);
if (fmt_unpack->unpack_s_8uint)
fmt_unpack->unpack_s_8uint(&stencil, 0, data, 0, 1, 1);
clear_depth_stencil(ice, p_res, level, box, true, true, true,
depth, stencil);
} else {
union isl_color_value color;
struct crocus_resource *res = (void *) p_res;
enum isl_format format = res->surf.format;
if (!isl_format_supports_rendering(devinfo, format)) {
const struct isl_format_layout *fmtl = isl_format_get_layout(format);
// XXX: actually just get_copy_format_for_bpb from BLORP
// XXX: don't cut and paste this
switch (fmtl->bpb) {
case 8: format = ISL_FORMAT_R8_UINT; break;
case 16: format = ISL_FORMAT_R8G8_UINT; break;
case 24: format = ISL_FORMAT_R8G8B8_UINT; break;
case 32: format = ISL_FORMAT_R8G8B8A8_UINT; break;
case 48: format = ISL_FORMAT_R16G16B16_UINT; break;
case 64: format = ISL_FORMAT_R16G16B16A16_UINT; break;
case 96: format = ISL_FORMAT_R32G32B32_UINT; break;
case 128: format = ISL_FORMAT_R32G32B32A32_UINT; break;
default:
UNREACHABLE("Unknown format bpb");
}
/* No aux surfaces for non-renderable surfaces */
assert(res->aux.usage == ISL_AUX_USAGE_NONE);
}
isl_color_value_unpack(&color, format, data);
clear_color(ice, p_res, level, box, true, format,
ISL_SWIZZLE_IDENTITY, color);
}
}
/**
* The pipe->clear_render_target() driver hook.
*
* This clears the given render target surface.
*/
static void
crocus_clear_render_target(struct pipe_context *ctx,
struct pipe_surface *psurf,
const union pipe_color_union *p_color,
unsigned dst_x, unsigned dst_y,
unsigned width, unsigned height,
bool render_condition_enabled)
{
struct crocus_context *ice = (void *) ctx;
struct crocus_surface *isurf = (void *) psurf;
struct pipe_box box = {
.x = dst_x,
.y = dst_y,
.z = psurf->first_layer,
.width = width,
.height = height,
.depth = psurf->last_layer - psurf->first_layer + 1
};
/* pipe_color_union and isl_color_value are interchangeable */
union isl_color_value *color = (void *) p_color;
clear_color(ice, psurf->texture, psurf->level, &box,
render_condition_enabled,
isurf->view.format, isurf->view.swizzle, *color);
}
/**
* The pipe->clear_depth_stencil() driver hook.
*
* This clears the given depth/stencil surface.
*/
static void
crocus_clear_depth_stencil(struct pipe_context *ctx,
struct pipe_surface *psurf,
unsigned flags,
double depth,
unsigned stencil,
unsigned dst_x, unsigned dst_y,
unsigned width, unsigned height,
bool render_condition_enabled)
{
return;
#if 0
struct crocus_context *ice = (void *) ctx;
struct pipe_box box = {
.x = dst_x,
.y = dst_y,
.z = psurf->first_layer,
.width = width,
.height = height,
.depth = psurf->last_layer - psurf->first_layer + 1
};
uint32_t blit_flags = 0;
assert(util_format_is_depth_or_stencil(psurf->texture->format));
crocus_blitter_begin(ice, CROCUS_SAVE_FRAGMENT_STATE);
util_blitter_clear(ice->blitter, width, height,
1, flags, NULL, depth, stencil, render_condition_enabled);
#if 0
clear_depth_stencil(ice, psurf->texture, psurf->level, &box,
render_condition_enabled,
flags & PIPE_CLEAR_DEPTH, flags & PIPE_CLEAR_STENCIL,
depth, stencil);
#endif
#endif
}
void
crocus_init_clear_functions(struct pipe_context *ctx)
{
ctx->clear = crocus_clear;
ctx->clear_texture = crocus_clear_texture;
ctx->clear_render_target = crocus_clear_render_target;
ctx->clear_depth_stencil = crocus_clear_depth_stencil;
}
+365
View File
@@ -0,0 +1,365 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <time.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "util/ralloc.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "util/u_upload_mgr.h"
#include "drm-uapi/i915_drm.h"
#include "crocus_context.h"
#include "crocus_perf.h"
#include "crocus_resource.h"
#include "crocus_screen.h"
#include "common/i915/intel_defines.h"
#include "common/intel_debug_identifier.h"
#include "common/intel_sample_positions.h"
/**
* The pipe->set_debug_callback() driver hook.
*/
static void
crocus_set_debug_callback(struct pipe_context *ctx,
const struct util_debug_callback *cb)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
if (cb)
ice->dbg = *cb;
else
memset(&ice->dbg, 0, sizeof(ice->dbg));
}
static bool
crocus_init_identifier_bo(struct crocus_context *ice)
{
void *bo_map;
bo_map = crocus_bo_map(NULL, ice->workaround_bo, MAP_READ | MAP_WRITE);
if (!bo_map)
return false;
ice->workaround_bo->kflags |= EXEC_OBJECT_CAPTURE;
ice->workaround_offset = align(
intel_debug_write_identifiers(bo_map, 4096, "Crocus"), 32);
crocus_bo_unmap(ice->workaround_bo);
return true;
}
/**
* Called from the batch module when it detects a GPU hang.
*
* In this case, we've lost our GEM context, and can't rely on any existing
* state on the GPU. We must mark everything dirty and wipe away any saved
* assumptions about the last known state of the GPU.
*/
void
crocus_lost_context_state(struct crocus_batch *batch)
{
/* The batch module doesn't have an crocus_context, because we want to
* avoid introducing lots of layering violations. Unfortunately, here
* we do need to inform the context of batch catastrophe. We know the
* batch is one of our context's, so hackily claw our way back.
*/
struct crocus_context *ice = batch->ice;
struct crocus_screen *screen = batch->screen;
if (batch->name == CROCUS_BATCH_RENDER) {
screen->vtbl.init_render_context(batch);
} else if (batch->name == CROCUS_BATCH_COMPUTE) {
screen->vtbl.init_compute_context(batch);
} else {
UNREACHABLE("unhandled batch reset");
}
ice->state.dirty = ~0ull;
memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
batch->state_base_address_emitted = false;
screen->vtbl.lost_genx_state(ice, batch);
}
static enum pipe_reset_status
crocus_get_device_reset_status(struct pipe_context *ctx)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
enum pipe_reset_status worst_reset = PIPE_NO_RESET;
/* Check the reset status of each batch's hardware context, and take the
* worst status (if one was guilty, proclaim guilt).
*/
for (int i = 0; i < ice->batch_count; i++) {
/* This will also recreate the hardware contexts as necessary, so any
* future queries will show no resets. We only want to report once.
*/
enum pipe_reset_status batch_reset =
crocus_batch_check_for_reset(&ice->batches[i]);
if (batch_reset == PIPE_NO_RESET)
continue;
if (worst_reset == PIPE_NO_RESET) {
worst_reset = batch_reset;
} else {
/* GUILTY < INNOCENT < UNKNOWN */
worst_reset = MIN2(worst_reset, batch_reset);
}
}
if (worst_reset != PIPE_NO_RESET && ice->reset.reset)
ice->reset.reset(ice->reset.data, worst_reset);
return worst_reset;
}
static void
crocus_set_device_reset_callback(struct pipe_context *ctx,
const struct pipe_device_reset_callback *cb)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
if (cb)
ice->reset = *cb;
else
memset(&ice->reset, 0, sizeof(ice->reset));
}
static void
crocus_get_sample_position(struct pipe_context *ctx,
unsigned sample_count,
unsigned sample_index,
float *out_value)
{
union {
struct {
float x[8];
float y[8];
} a;
struct {
float _0XOffset, _1XOffset, _2XOffset, _3XOffset,
_4XOffset, _5XOffset, _6XOffset, _7XOffset;
float _0YOffset, _1YOffset, _2YOffset, _3YOffset,
_4YOffset, _5YOffset, _6YOffset, _7YOffset;
} v;
} u;
switch (sample_count) {
case 1: INTEL_SAMPLE_POS_1X(u.v._); break;
case 2: INTEL_SAMPLE_POS_2X(u.v._); break;
case 4: INTEL_SAMPLE_POS_4X(u.v._); break;
case 8: INTEL_SAMPLE_POS_8X(u.v._); break;
default: UNREACHABLE("invalid sample count");
}
out_value[0] = u.a.x[sample_index];
out_value[1] = u.a.y[sample_index];
}
#define genX_call(devinfo, func, ...) \
switch ((devinfo)->verx10) { \
case 80: \
gfx8_##func(__VA_ARGS__); \
break; \
case 75: \
gfx75_##func(__VA_ARGS__); \
break; \
case 70: \
gfx7_##func(__VA_ARGS__); \
break; \
case 60: \
gfx6_##func(__VA_ARGS__); \
break; \
case 50: \
gfx5_##func(__VA_ARGS__); \
break; \
case 45: \
gfx45_##func(__VA_ARGS__); \
break; \
case 40: \
gfx4_##func(__VA_ARGS__); \
break; \
default: \
UNREACHABLE("Unknown hardware generation"); \
}
/**
* Destroy a context, freeing any associated memory.
*/
static void
crocus_destroy_context(struct pipe_context *ctx)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
const struct intel_device_info *devinfo = &screen->devinfo;
blorp_finish(&ice->blorp);
intel_perf_free_context(ice->perf_ctx);
if (ctx->stream_uploader)
u_upload_destroy(ctx->stream_uploader);
if (ice->blitter)
util_blitter_destroy(ice->blitter);
screen->vtbl.destroy_state(ice);
genX_call(devinfo, crocus_framebuffer_init, ctx, NULL, ice->state.fb_cbufs, &ice->state.fb_zsbuf);
util_unreference_framebuffer_state(&ice->state.framebuffer);
for (unsigned i = 0; i < ARRAY_SIZE(ice->shaders.scratch_bos); i++) {
for (unsigned j = 0; j < ARRAY_SIZE(ice->shaders.scratch_bos[i]); j++)
crocus_bo_unreference(ice->shaders.scratch_bos[i][j]);
}
crocus_destroy_program_cache(ice);
u_upload_destroy(ice->query_buffer_uploader);
crocus_bo_unreference(ice->workaround_bo);
slab_destroy_child(&ice->transfer_pool);
slab_destroy_child(&ice->transfer_pool_unsync);
crocus_batch_free(&ice->batches[CROCUS_BATCH_RENDER]);
if (ice->batches[CROCUS_BATCH_COMPUTE].ice)
crocus_batch_free(&ice->batches[CROCUS_BATCH_COMPUTE]);
ralloc_free(ice);
}
/**
* Create a context.
*
* This is where each context begins.
*/
struct pipe_context *
crocus_create_context(struct pipe_screen *pscreen, void *priv, unsigned flags)
{
struct crocus_screen *screen = (struct crocus_screen*)pscreen;
const struct intel_device_info *devinfo = &screen->devinfo;
struct crocus_context *ice = rzalloc(NULL, struct crocus_context);
if (!ice)
return NULL;
struct pipe_context *ctx = &ice->ctx;
ctx->screen = pscreen;
ctx->priv = priv;
ctx->stream_uploader = u_upload_create_default(ctx);
if (!ctx->stream_uploader) {
ralloc_free(ice);
return NULL;
}
ctx->const_uploader = ctx->stream_uploader;
ctx->destroy = crocus_destroy_context;
ctx->set_debug_callback = crocus_set_debug_callback;
ctx->set_device_reset_callback = crocus_set_device_reset_callback;
ctx->get_device_reset_status = crocus_get_device_reset_status;
ctx->get_sample_position = crocus_get_sample_position;
ice->shaders.urb_size = devinfo->urb.size;
crocus_init_context_fence_functions(ctx);
crocus_init_blit_functions(ctx);
crocus_init_clear_functions(ctx);
crocus_init_program_functions(ctx);
crocus_init_resource_functions(ctx);
crocus_init_flush_functions(ctx);
crocus_init_perfquery_functions(ctx);
crocus_init_program_cache(ice);
slab_create_child(&ice->transfer_pool, &screen->transfer_pool);
slab_create_child(&ice->transfer_pool_unsync, &screen->transfer_pool);
ice->query_buffer_uploader =
u_upload_create(ctx, 4096, PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING,
0);
ice->workaround_bo =
crocus_bo_alloc(screen->bufmgr, "workaround", 4096);
if (!ice->workaround_bo)
return NULL;
if (!crocus_init_identifier_bo(ice))
return NULL;
genX_call(devinfo, crocus_init_state, ice);
genX_call(devinfo, crocus_init_blorp, ice);
genX_call(devinfo, crocus_init_query, ice);
ice->blitter = util_blitter_create(&ice->ctx);
if (ice->blitter == NULL)
return NULL;
int priority = 0;
if (flags & PIPE_CONTEXT_HIGH_PRIORITY)
priority = INTEL_CONTEXT_HIGH_PRIORITY;
if (flags & PIPE_CONTEXT_LOW_PRIORITY)
priority = INTEL_CONTEXT_LOW_PRIORITY;
ice->batch_count = devinfo->ver >= 7 ? CROCUS_BATCH_COUNT : 1;
for (int i = 0; i < ice->batch_count; i++) {
crocus_init_batch(ice, (enum crocus_batch_name) i,
priority);
}
ice->urb.size = devinfo->urb.size;
screen->vtbl.init_render_context(&ice->batches[CROCUS_BATCH_RENDER]);
if (ice->batch_count > 1)
screen->vtbl.init_compute_context(&ice->batches[CROCUS_BATCH_COMPUTE]);
if (!(flags & PIPE_CONTEXT_PREFER_THREADED)) {
fprintf(stderr, "CROCUS unthreaded context: get_compute_state_info=%p, set_global_binding=%p\n",
ctx->get_compute_state_info, ctx->set_global_binding);
return ctx;
}
struct pipe_context *tc = threaded_context_create(ctx, &screen->transfer_pool,
crocus_replace_buffer_storage,
NULL, /* TODO: asynchronous flushes? */
&ice->thrctx);
fprintf(stderr, "CROCUS threaded context: get_compute_state_info=%p, set_global_binding=%p\n",
tc->get_compute_state_info, tc->set_global_binding);
return tc;
}
bool
crocus_sw_check_cond_render(struct crocus_context *ice)
{
struct crocus_query *q = ice->condition.query;
union pipe_query_result result;
bool wait = ice->condition.mode == PIPE_RENDER_COND_WAIT ||
ice->condition.mode == PIPE_RENDER_COND_BY_REGION_WAIT;
if (!q)
return true;
bool ret = ice->ctx.get_query_result(&ice->ctx, (void *)q, wait, &result);
if (!ret)
return true;
return ice->condition.condition ? result.u64 == 0 : result.u64 != 0;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,58 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CROCUS_DEFINES_H
#define CROCUS_DEFINES_H
/**
* @file crocus_defines.h
*
* Random hardware #defines that we're not using GENXML for.
*/
#define MI_PREDICATE (0xC << 23)
# define MI_PREDICATE_LOADOP_KEEP (0 << 6)
# define MI_PREDICATE_LOADOP_LOAD (2 << 6)
# define MI_PREDICATE_LOADOP_LOADINV (3 << 6)
# define MI_PREDICATE_COMBINEOP_SET (0 << 3)
# define MI_PREDICATE_COMBINEOP_AND (1 << 3)
# define MI_PREDICATE_COMBINEOP_OR (2 << 3)
# define MI_PREDICATE_COMBINEOP_XOR (3 << 3)
# define MI_PREDICATE_COMPAREOP_TRUE (0 << 0)
# define MI_PREDICATE_COMPAREOP_FALSE (1 << 0)
# define MI_PREDICATE_COMPAREOP_SRCS_EQUAL (2 << 0)
# define MI_PREDICATE_COMPAREOP_DELTAS_EQUAL (3 << 0)
/* Predicate registers */
#define MI_PREDICATE_SRC0 0x2400
#define MI_PREDICATE_SRC1 0x2408
#define MI_PREDICATE_DATA 0x2410
#define MI_PREDICATE_RESULT 0x2418
#define MI_PREDICATE_RESULT_1 0x241C
#define MI_PREDICATE_RESULT_2 0x2214
#define CS_GPR(n) (0x2600 + (n) * 8)
/* The number of bits in our TIMESTAMP queries. */
#define TIMESTAMP_BITS 36
#endif
@@ -0,0 +1,260 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_disk_cache.c
*
* Functions for interacting with the on-disk shader cache.
*/
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "compiler/nir/nir.h"
#include "util/blob.h"
#include "util/build_id.h"
#include "util/disk_cache.h"
#include "util/mesa-blake3.h"
#include "crocus_context.h"
static bool debug = false;
/**
* Compute a disk cache key for the given uncompiled shader and NOS key.
*/
static void
crocus_disk_cache_compute_key(struct disk_cache *cache,
const struct crocus_uncompiled_shader *ish,
const void *orig_prog_key,
uint32_t prog_key_size,
cache_key cache_key)
{
/* Create a copy of the program key with program_string_id zeroed out.
* It's essentially random data which we don't want to include in our
* hashing and comparisons. We'll set a proper value on a cache hit.
*/
union elk_any_prog_key prog_key;
memcpy(&prog_key, orig_prog_key, prog_key_size);
prog_key.base.program_string_id = 0;
uint8_t data[sizeof(prog_key) + sizeof(ish->nir_blake3)];
uint32_t data_size = prog_key_size + sizeof(ish->nir_blake3);
memcpy(data, ish->nir_blake3, sizeof(ish->nir_blake3));
memcpy(data + sizeof(ish->nir_blake3), &prog_key, prog_key_size);
disk_cache_compute_key(cache, data, data_size, cache_key);
}
/**
* Store the given compiled shader in the disk cache.
*
* This should only be called on newly compiled shaders. No checking is
* done to prevent repeated stores of the same shader.
*/
void
crocus_disk_cache_store(struct disk_cache *cache,
const struct crocus_uncompiled_shader *ish,
const struct crocus_compiled_shader *shader,
void *map,
const void *prog_key,
uint32_t prog_key_size)
{
#ifdef ENABLE_SHADER_CACHE
if (!cache)
return;
mesa_shader_stage stage = ish->nir->info.stage;
const struct elk_stage_prog_data *prog_data = shader->prog_data;
cache_key cache_key;
crocus_disk_cache_compute_key(cache, ish, prog_key, prog_key_size, cache_key);
if (debug) {
char blake3[BLAKE3_HEX_LEN];
_mesa_blake3_format(blake3, cache_key);
fprintf(stderr, "[mesa disk cache] storing %s\n", blake3);
}
struct blob blob;
blob_init(&blob);
/* We write the following data to the cache blob:
*
* 1. Prog data (must come first because it has the assembly size)
* 2. Assembly code
* 3. Number of entries in the system value array
* 4. System value array
* 5. Legacy param array (only used for compute workgroup ID)
* 6. Binding table
*/
blob_write_bytes(&blob, shader->prog_data, elk_prog_data_size(stage));
blob_write_bytes(&blob, map + shader->offset, shader->prog_data->program_size);
blob_write_bytes(&blob, &shader->num_system_values, sizeof(unsigned));
blob_write_bytes(&blob, shader->system_values,
shader->num_system_values * sizeof(enum elk_param_builtin));
blob_write_bytes(&blob, prog_data->param,
prog_data->nr_params * sizeof(uint32_t));
blob_write_bytes(&blob, &shader->bt, sizeof(shader->bt));
disk_cache_put(cache, cache_key, blob.data, blob.size, NULL);
blob_finish(&blob);
#endif
}
/**
* Search for a compiled shader in the disk cache. If found, upload it
* to the in-memory program cache so we can use it.
*/
struct crocus_compiled_shader *
crocus_disk_cache_retrieve(struct crocus_context *ice,
const struct crocus_uncompiled_shader *ish,
const void *prog_key,
uint32_t key_size)
{
#ifdef ENABLE_SHADER_CACHE
struct crocus_screen *screen = (void *) ice->ctx.screen;
struct disk_cache *cache = screen->disk_cache;
mesa_shader_stage stage = ish->nir->info.stage;
if (!cache)
return NULL;
cache_key cache_key;
crocus_disk_cache_compute_key(cache, ish, prog_key, key_size, cache_key);
if (debug) {
char blake3[BLAKE3_HEX_LEN];
_mesa_blake3_format(blake3, cache_key);
fprintf(stderr, "[mesa disk cache] retrieving %s: ", blake3);
}
size_t size;
void *buffer = disk_cache_get(screen->disk_cache, cache_key, &size);
if (debug)
fprintf(stderr, "%s\n", buffer ? "found" : "missing");
if (!buffer)
return NULL;
const uint32_t prog_data_size = elk_prog_data_size(stage);
struct elk_stage_prog_data *prog_data = ralloc_size(NULL, prog_data_size);
const void *assembly;
uint32_t num_system_values;
uint32_t *system_values = NULL;
uint32_t *so_decls = NULL;
struct blob_reader blob;
blob_reader_init(&blob, buffer, size);
blob_copy_bytes(&blob, prog_data, prog_data_size);
assembly = blob_read_bytes(&blob, prog_data->program_size);
num_system_values = blob_read_uint32(&blob);
if (num_system_values) {
system_values =
ralloc_array(NULL, enum elk_param_builtin, num_system_values);
blob_copy_bytes(&blob, system_values,
num_system_values * sizeof(enum elk_param_builtin));
}
prog_data->param = NULL;
if (prog_data->nr_params) {
prog_data->param = ralloc_array(NULL, uint32_t, prog_data->nr_params);
blob_copy_bytes(&blob, prog_data->param,
prog_data->nr_params * sizeof(uint32_t));
}
struct crocus_binding_table bt;
blob_copy_bytes(&blob, &bt, sizeof(bt));
if ((stage == MESA_SHADER_VERTEX ||
stage == MESA_SHADER_TESS_EVAL ||
stage == MESA_SHADER_GEOMETRY) && screen->devinfo.ver > 6) {
struct elk_vue_prog_data *vue_prog_data = (void *) prog_data;
so_decls = screen->vtbl.create_so_decl_list(&ish->stream_output,
&vue_prog_data->vue_map);
}
/* System values and uniforms are stored in constant buffer 0, the
* user-facing UBOs are indexed by one. So if any constant buffer is
* needed, the constant buffer 0 will be needed, so account for it.
*/
unsigned num_cbufs = ish->nir->info.num_ubos;
if (num_cbufs || ish->nir->num_uniforms)
num_cbufs++;
if (num_system_values)
num_cbufs++;
/* Upload our newly read shader to the in-memory program cache and
* return it to the caller.
*/
struct crocus_compiled_shader *shader =
crocus_upload_shader(ice, stage, key_size, prog_key, assembly,
prog_data->program_size,
prog_data, prog_data_size, so_decls, system_values,
num_system_values, num_cbufs, &bt);
free(buffer);
return shader;
#else
return NULL;
#endif
}
/**
* Initialize the on-disk shader cache.
*/
void
crocus_disk_cache_init(struct crocus_screen *screen)
{
#ifdef ENABLE_SHADER_CACHE
if (INTEL_DEBUG(DEBUG_DISK_CACHE_DISABLE_MASK))
return;
/* array length = print length + nul char + 1 extra to verify it's unused */
char renderer[13];
UNUSED int len =
snprintf(renderer, sizeof(renderer), "crocus_%04x", screen->pci_id);
assert(len == sizeof(renderer) - 2);
const struct build_id_note *note =
build_id_find_nhdr_for_addr(crocus_disk_cache_init);
assert(note && build_id_length(note) == BUILD_ID_EXPECTED_HASH_LENGTH); /* sha1 */
const uint8_t *id_sha1 = build_id_data(note);
assert(id_sha1);
char timestamp[BLAKE3_HEX_LEN];
_mesa_sha1_format(timestamp, id_sha1);
const uint64_t driver_flags =
elk_get_compiler_config_value(screen->compiler);
screen->disk_cache = disk_cache_create(renderer, timestamp, driver_flags);
#endif
}
+530
View File
@@ -0,0 +1,530 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_draw.c
*
* The main driver hooks for drawing and launching compute shaders.
*/
#include <stdio.h>
#include <errno.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/u_draw.h"
#include "util/u_inlines.h"
#include "util/u_transfer.h"
#include "util/u_upload_mgr.h"
#include "intel/compiler/elk/elk_compiler.h"
#include "intel/compiler/elk/elk_eu_defines.h"
#include "compiler/shader_info.h"
#include "crocus_context.h"
#include "crocus_defines.h"
#include "util/u_prim_restart.h"
#include "util/u_prim.h"
static bool
prim_is_points_or_lines(enum mesa_prim mode)
{
/* We don't need to worry about adjacency - it can only be used with
* geometry shaders, and we don't care about this info when GS is on.
*/
return mode == MESA_PRIM_POINTS ||
mode == MESA_PRIM_LINES ||
mode == MESA_PRIM_LINE_LOOP ||
mode == MESA_PRIM_LINE_STRIP;
}
static bool
can_cut_index_handle_restart_index(struct crocus_context *ice,
const struct pipe_draw_info *draw)
{
switch (draw->index_size) {
case 1:
return draw->restart_index == 0xff;
case 2:
return draw->restart_index == 0xffff;
case 4:
return draw->restart_index == 0xffffffff;
default:
UNREACHABLE("illegal index size\n");
}
return false;
}
static bool
can_cut_index_handle_prim(struct crocus_context *ice,
const struct pipe_draw_info *draw)
{
struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
const struct intel_device_info *devinfo = &screen->devinfo;
/* Haswell can do it all. */
if (devinfo->verx10 >= 75)
return true;
if (!can_cut_index_handle_restart_index(ice, draw))
return false;
switch (draw->mode) {
case MESA_PRIM_POINTS:
case MESA_PRIM_LINES:
case MESA_PRIM_LINE_STRIP:
case MESA_PRIM_TRIANGLES:
case MESA_PRIM_TRIANGLE_STRIP:
case MESA_PRIM_LINES_ADJACENCY:
case MESA_PRIM_LINE_STRIP_ADJACENCY:
case MESA_PRIM_TRIANGLES_ADJACENCY:
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY:
return true;
default:
break;
}
return false;
}
/**
* Record the current primitive mode and restart information, flagging
* related packets as dirty if necessary.
*
* This must be called before updating compiled shaders, because the patch
* information informs the TCS key.
*/
static void
crocus_update_draw_info(struct crocus_context *ice,
const struct pipe_draw_info *info,
const struct pipe_draw_start_count_bias *draw)
{
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
enum mesa_prim mode = info->mode;
if (screen->devinfo.ver < 6) {
/* Slight optimization to avoid the GS program when not needed:
*/
struct pipe_rasterizer_state *rs_state = crocus_get_rast_state(ice);
if (mode == MESA_PRIM_QUAD_STRIP && !rs_state->flatshade &&
rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
mode = MESA_PRIM_TRIANGLE_STRIP;
if (mode == MESA_PRIM_QUADS &&
draw->count == 4 &&
!rs_state->flatshade &&
rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
mode = MESA_PRIM_TRIANGLE_FAN;
}
if (ice->state.prim_mode != mode) {
ice->state.prim_mode = mode;
enum mesa_prim reduced = u_reduced_prim(mode);
if (ice->state.reduced_prim_mode != reduced) {
if (screen->devinfo.ver < 6)
ice->state.dirty |= CROCUS_DIRTY_GEN4_CLIP_PROG | CROCUS_DIRTY_GEN4_SF_PROG;
/* if the reduced prim changes the WM needs updating. */
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_FS;
ice->state.reduced_prim_mode = reduced;
}
if (screen->devinfo.ver == 8)
ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
if (screen->devinfo.ver <= 6)
ice->state.dirty |= CROCUS_DIRTY_GEN4_FF_GS_PROG;
if (screen->devinfo.ver >= 7)
ice->state.dirty |= CROCUS_DIRTY_GEN7_SBE;
/* For XY Clip enables */
bool points_or_lines = prim_is_points_or_lines(mode);
if (points_or_lines != ice->state.prim_is_points_or_lines) {
ice->state.prim_is_points_or_lines = points_or_lines;
ice->state.dirty |= CROCUS_DIRTY_CLIP;
}
}
if (info->mode == MESA_PRIM_PATCHES &&
ice->state.vertices_per_patch != ice->state.patch_vertices) {
ice->state.vertices_per_patch = ice->state.patch_vertices;
if (screen->devinfo.ver == 8)
ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
/* This is needed for key->input_vertices */
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_TCS;
/* Flag constants dirty for gl_PatchVerticesIn if needed. */
const struct shader_info *tcs_info =
crocus_get_shader_info(ice, MESA_SHADER_TESS_CTRL);
if (tcs_info &&
BITSET_TEST(tcs_info->system_values_read, SYSTEM_VALUE_VERTICES_IN)) {
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_TCS;
ice->state.shaders[MESA_SHADER_TESS_CTRL].sysvals_need_upload = true;
}
}
const unsigned cut_index = info->primitive_restart ? info->restart_index :
ice->state.cut_index;
if (ice->state.primitive_restart != info->primitive_restart ||
ice->state.cut_index != cut_index) {
if (screen->devinfo.verx10 >= 75)
ice->state.dirty |= CROCUS_DIRTY_GEN75_VF;
ice->state.primitive_restart = info->primitive_restart;
ice->state.cut_index = info->restart_index;
}
}
/**
* Update shader draw parameters, flagging VF packets as dirty if necessary.
*/
static void
crocus_update_draw_parameters(struct crocus_context *ice,
const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *draw)
{
bool changed = false;
if (ice->state.vs_uses_draw_params) {
struct crocus_state_ref *draw_params = &ice->draw.draw_params;
if (indirect && indirect->buffer) {
pipe_resource_reference(&draw_params->res, indirect->buffer);
draw_params->offset =
indirect->offset + (info->index_size ? 12 : 8);
changed = true;
ice->draw.params_valid = false;
} else {
int firstvertex = info->index_size ? draw->index_bias : draw->start;
if (!ice->draw.params_valid ||
ice->draw.params.firstvertex != firstvertex ||
ice->draw.params.baseinstance != info->start_instance) {
changed = true;
ice->draw.params.firstvertex = firstvertex;
ice->draw.params.baseinstance = info->start_instance;
ice->draw.params_valid = true;
u_upload_data_ref(ice->ctx.stream_uploader, 0,
sizeof(ice->draw.params), 4, &ice->draw.params,
&draw_params->offset, &draw_params->res);
}
}
}
if (ice->state.vs_uses_derived_draw_params) {
struct crocus_state_ref *derived_params = &ice->draw.derived_draw_params;
int is_indexed_draw = info->index_size ? -1 : 0;
if (ice->draw.derived_params.drawid != drawid_offset ||
ice->draw.derived_params.is_indexed_draw != is_indexed_draw) {
changed = true;
ice->draw.derived_params.drawid = drawid_offset;
ice->draw.derived_params.is_indexed_draw = is_indexed_draw;
u_upload_data_ref(ice->ctx.stream_uploader, 0,
sizeof(ice->draw.derived_params), 4,
&ice->draw.derived_params, &derived_params->offset,
&derived_params->res);
}
}
if (changed) {
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
ice->state.dirty |= CROCUS_DIRTY_VERTEX_BUFFERS |
CROCUS_DIRTY_VERTEX_ELEMENTS;
if (screen->devinfo.ver == 8)
ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_SGVS;
}
}
static void
crocus_indirect_draw_vbo(struct crocus_context *ice,
const struct pipe_draw_info *dinfo,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *dindirect,
const struct pipe_draw_start_count_bias *draws)
{
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_screen *screen = batch->screen;
struct pipe_draw_info info = *dinfo;
struct pipe_draw_indirect_info indirect = *dindirect;
const struct intel_device_info *devinfo = &batch->screen->devinfo;
if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
/* Upload MI_PREDICATE_RESULT to GPR15.*/
screen->vtbl.load_register_reg64(batch, CS_GPR(15), MI_PREDICATE_RESULT);
}
uint64_t orig_dirty = ice->state.dirty;
uint64_t orig_stage_dirty = ice->state.stage_dirty;
for (int i = 0; i < indirect.draw_count; i++) {
crocus_batch_maybe_flush(batch, 1500);
crocus_require_statebuffer_space(batch, 2400);
if (ice->state.vs_uses_draw_params ||
ice->state.vs_uses_derived_draw_params)
crocus_update_draw_parameters(ice, &info, drawid_offset + i, &indirect, draws);
screen->vtbl.upload_render_state(ice, batch, &info, drawid_offset + i, &indirect, draws);
ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
indirect.offset += indirect.stride;
}
if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
/* Restore MI_PREDICATE_RESULT. */
screen->vtbl.load_register_reg64(batch, MI_PREDICATE_RESULT, CS_GPR(15));
}
/* Put this back for post-draw resolves, we'll clear it again after. */
ice->state.dirty = orig_dirty;
ice->state.stage_dirty = orig_stage_dirty;
}
static void
crocus_simple_draw_vbo(struct crocus_context *ice,
const struct pipe_draw_info *draw,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *sc)
{
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_screen *screen = batch->screen;
crocus_batch_maybe_flush(batch, 1500);
crocus_require_statebuffer_space(batch, 2400);
if (ice->state.vs_uses_draw_params ||
ice->state.vs_uses_derived_draw_params)
crocus_update_draw_parameters(ice, draw, drawid_offset, indirect, sc);
screen->vtbl.upload_render_state(ice, batch, draw, drawid_offset, indirect, sc);
}
static void
crocus_draw_vbo_get_vertex_count(struct pipe_context *ctx,
const struct pipe_draw_info *info_in,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect)
{
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
struct pipe_draw_info info = *info_in;
struct pipe_draw_start_count_bias draw;
uint32_t val = screen->vtbl.get_so_offset(indirect->count_from_stream_output);
draw.start = 0;
draw.count = val;
ctx->draw_vbo(ctx, &info, drawid_offset, NULL, &draw, 1);
}
/**
* The pipe->draw_vbo() driver hook. Performs a draw on the GPU.
*/
void
crocus_draw_vbo(struct pipe_context *ctx,
const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws)
{
if (num_draws > 1) {
util_draw_multi(ctx, info, drawid_offset, indirect, draws, num_draws);
return;
}
if (!indirect && (!draws[0].count || !info->instance_count))
return;
struct crocus_context *ice = (struct crocus_context *) ctx;
struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
if (!crocus_check_conditional_render(ice))
return;
if (info->primitive_restart && !can_cut_index_handle_prim(ice, info)) {
util_draw_vbo_without_prim_restart(ctx, info, drawid_offset,
indirect, draws);
return;
}
if (screen->devinfo.verx10 < 75 &&
indirect && indirect->count_from_stream_output) {
crocus_draw_vbo_get_vertex_count(ctx, info, drawid_offset, indirect);
return;
}
/**
* The hardware is capable of removing dangling vertices on its own; however,
* prior to Gen6, we sometimes convert quads into trifans (and quad strips
* into tristrips), since pre-Gen6 hardware requires a GS to render quads.
* This function manually trims dangling vertices from a draw call involving
* quads so that those dangling vertices won't get drawn when we convert to
* trifans/tristrips.
*/
if (screen->devinfo.ver < 6) {
if (info->mode == MESA_PRIM_QUADS || info->mode == MESA_PRIM_QUAD_STRIP) {
bool trim = u_trim_pipe_prim(info->mode, (unsigned *)&draws[0].count);
if (!trim)
return;
}
}
/* We can't safely re-emit 3DSTATE_SO_BUFFERS because it may zero the
* write offsets, changing the behavior.
*/
if (INTEL_DEBUG(DEBUG_REEMIT)) {
ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_RENDER & ~(CROCUS_DIRTY_GEN7_SO_BUFFERS | CROCUS_DIRTY_GEN6_SVBI);
ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
}
/* Emit Sandybridge workaround flushes on every primitive, for safety. */
if (screen->devinfo.ver == 6)
crocus_emit_post_sync_nonzero_flush(batch);
crocus_update_draw_info(ice, info, draws);
if (!crocus_update_compiled_shaders(ice))
return;
if (ice->state.dirty & CROCUS_DIRTY_RENDER_RESOLVES_AND_FLUSHES) {
bool draw_aux_buffer_disabled[ELK_MAX_DRAW_BUFFERS] = { };
for (mesa_shader_stage stage = 0; stage < MESA_SHADER_COMPUTE; stage++) {
if (ice->shaders.prog[stage])
crocus_predraw_resolve_inputs(ice, batch, draw_aux_buffer_disabled,
stage, true);
}
crocus_predraw_resolve_framebuffer(ice, batch, draw_aux_buffer_disabled);
}
crocus_handle_always_flush_cache(batch);
if (indirect && indirect->buffer)
crocus_indirect_draw_vbo(ice, info, drawid_offset, indirect, draws);
else
crocus_simple_draw_vbo(ice, info, drawid_offset, indirect, draws);
crocus_handle_always_flush_cache(batch);
crocus_postdraw_update_resolve_tracking(ice, batch);
ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
}
static void
crocus_update_grid_size_resource(struct crocus_context *ice,
const struct pipe_grid_info *grid)
{
struct crocus_state_ref *grid_ref = &ice->state.grid_size;
const struct crocus_compiled_shader *shader = ice->shaders.prog[MESA_SHADER_COMPUTE];
bool grid_needs_surface = shader->bt.used_mask[CROCUS_SURFACE_GROUP_CS_WORK_GROUPS];
if (grid->indirect) {
pipe_resource_reference(&grid_ref->res, grid->indirect);
grid_ref->offset = grid->indirect_offset;
/* Zero out the grid size so that the next non-indirect grid launch will
* re-upload it properly.
*/
memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
} else if (memcmp(ice->state.last_grid, grid->grid, sizeof(grid->grid)) != 0) {
memcpy(ice->state.last_grid, grid->grid, sizeof(grid->grid));
u_upload_data_ref(ice->ctx.const_uploader, 0, sizeof(grid->grid), 4,
grid->grid, &grid_ref->offset, &grid_ref->res);
}
/* Skip surface upload if we don't need it or we already have one */
if (!grid_needs_surface)
return;
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_BINDINGS_CS;
}
void
crocus_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *grid)
{
struct crocus_context *ice = (struct crocus_context *) ctx;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_COMPUTE];
struct crocus_screen *screen = batch->screen;
if (!crocus_check_conditional_render(ice))
return;
if (INTEL_DEBUG(DEBUG_REEMIT)) {
ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_COMPUTE;
ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
}
/* We can't do resolves on the compute engine, so awkwardly, we have to
* do them on the render batch...
*/
if (ice->state.dirty & CROCUS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES) {
crocus_predraw_resolve_inputs(ice, &ice->batches[CROCUS_BATCH_RENDER], NULL,
MESA_SHADER_COMPUTE, false);
}
crocus_batch_maybe_flush(batch, 1500);
crocus_require_statebuffer_space(batch, 2500);
crocus_update_compiled_compute_shader(ice);
if (memcmp(ice->state.last_block, grid->block, sizeof(grid->block)) != 0) {
memcpy(ice->state.last_block, grid->block, sizeof(grid->block));
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_CS;
ice->state.shaders[MESA_SHADER_COMPUTE].sysvals_need_upload = true;
}
crocus_update_grid_size_resource(ice, grid);
if (ice->state.compute_predicate) {
screen->vtbl.emit_compute_predicate(batch);
ice->state.compute_predicate = NULL;
}
crocus_handle_always_flush_cache(batch);
screen->vtbl.upload_compute_state(ice, batch, grid);
crocus_handle_always_flush_cache(batch);
ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_COMPUTE;
ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
/* Note: since compute shaders can't access the framebuffer, there's
* no need to call crocus_postdraw_update_resolve_tracking.
*/
}
+576
View File
@@ -0,0 +1,576 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_fence.c
*
* Fences for driver and IPC serialisation, scheduling and synchronisation.
*/
#include "util/u_inlines.h"
#include "intel/common/intel_gem.h"
#include "crocus_batch.h"
#include "crocus_bufmgr.h"
#include "crocus_context.h"
#include "crocus_fence.h"
#include "crocus_screen.h"
static uint32_t
gem_syncobj_create(int fd, uint32_t flags)
{
struct drm_syncobj_create args = {
.flags = flags,
};
intel_ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
return args.handle;
}
static void
gem_syncobj_destroy(int fd, uint32_t handle)
{
struct drm_syncobj_destroy args = {
.handle = handle,
};
intel_ioctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
}
/**
* Make a new sync-point.
*/
struct crocus_syncobj *
crocus_create_syncobj(struct crocus_screen *screen)
{
struct crocus_syncobj *syncobj = malloc(sizeof(*syncobj));
if (!syncobj)
return NULL;
syncobj->handle = gem_syncobj_create(screen->fd, 0);
assert(syncobj->handle);
pipe_reference_init(&syncobj->ref, 1);
return syncobj;
}
void
crocus_syncobj_destroy(struct crocus_screen *screen,
struct crocus_syncobj *syncobj)
{
gem_syncobj_destroy(screen->fd, syncobj->handle);
free(syncobj);
}
/**
* Add a sync-point to the batch, with the given flags.
*
* \p flags One of I915_EXEC_FENCE_WAIT or I915_EXEC_FENCE_SIGNAL.
*/
void
crocus_batch_add_syncobj(struct crocus_batch *batch,
struct crocus_syncobj *syncobj, unsigned flags)
{
struct drm_i915_gem_exec_fence *fence =
util_dynarray_grow(&batch->exec_fences, struct drm_i915_gem_exec_fence, 1);
*fence = (struct drm_i915_gem_exec_fence){
.handle = syncobj->handle,
.flags = flags,
};
struct crocus_syncobj **store =
util_dynarray_grow(&batch->syncobjs, struct crocus_syncobj *, 1);
*store = NULL;
crocus_syncobj_reference(batch->screen, store, syncobj);
}
/**
* Walk through a batch's dependencies (any I915_EXEC_FENCE_WAIT syncobjs)
* and unreference any which have already passed.
*
* Sometimes the compute batch is seldom used, and accumulates references
* to stale render batches that are no longer of interest, so we can free
* those up.
*/
static void
clear_stale_syncobjs(struct crocus_batch *batch)
{
struct crocus_screen *screen = batch->screen;
int n = util_dynarray_num_elements(&batch->syncobjs, struct crocus_syncobj *);
assert(n == util_dynarray_num_elements(&batch->exec_fences,
struct drm_i915_gem_exec_fence));
/* Skip the first syncobj, as it's the signalling one. */
for (int i = n - 1; i > 0; i--) {
struct crocus_syncobj **syncobj =
util_dynarray_element(&batch->syncobjs, struct crocus_syncobj *, i);
struct drm_i915_gem_exec_fence *fence =
util_dynarray_element(&batch->exec_fences,
struct drm_i915_gem_exec_fence, i);
assert(fence->flags & I915_EXEC_FENCE_WAIT);
if (crocus_wait_syncobj(&screen->base, *syncobj, 0))
continue;
/* This sync object has already passed, there's no need to continue
* marking it as a dependency; we can stop holding on to the reference.
*/
crocus_syncobj_reference(screen, syncobj, NULL);
/* Remove it from the lists; move the last element here. */
struct crocus_syncobj **nth_syncobj =
util_dynarray_pop_ptr(&batch->syncobjs, struct crocus_syncobj *);
struct drm_i915_gem_exec_fence *nth_fence =
util_dynarray_pop_ptr(&batch->exec_fences,
struct drm_i915_gem_exec_fence);
if (syncobj != nth_syncobj) {
*syncobj = *nth_syncobj;
memcpy(fence, nth_fence, sizeof(*fence));
}
}
}
/* ------------------------------------------------------------------- */
struct pipe_fence_handle {
struct pipe_reference ref;
struct pipe_context *unflushed_ctx;
struct crocus_fine_fence *fine[CROCUS_BATCH_COUNT];
};
static void
crocus_fence_destroy(struct pipe_screen *p_screen,
struct pipe_fence_handle *fence)
{
struct crocus_screen *screen = (struct crocus_screen *)p_screen;
for (unsigned i = 0; i < ARRAY_SIZE(fence->fine); i++)
crocus_fine_fence_reference(screen, &fence->fine[i], NULL);
free(fence);
}
static void
crocus_fence_reference(struct pipe_screen *p_screen,
struct pipe_fence_handle **dst,
struct pipe_fence_handle *src)
{
if (pipe_reference(&(*dst)->ref, &src->ref))
crocus_fence_destroy(p_screen, *dst);
*dst = src;
}
bool
crocus_wait_syncobj(struct pipe_screen *p_screen,
struct crocus_syncobj *syncobj, int64_t timeout_nsec)
{
if (!syncobj)
return false;
struct crocus_screen *screen = (struct crocus_screen *)p_screen;
struct drm_syncobj_wait args = {
.handles = (uintptr_t)&syncobj->handle,
.count_handles = 1,
.timeout_nsec = timeout_nsec,
};
return intel_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
}
static void
crocus_fence_flush(struct pipe_context *ctx,
struct pipe_fence_handle **out_fence, unsigned flags)
{
struct crocus_screen *screen = (void *)ctx->screen;
struct crocus_context *ice = (struct crocus_context *)ctx;
const bool deferred = flags & PIPE_FLUSH_DEFERRED;
if (!deferred) {
for (unsigned i = 0; i < ice->batch_count; i++)
crocus_batch_flush(&ice->batches[i]);
}
if (!out_fence)
return;
struct pipe_fence_handle *fence = calloc(1, sizeof(*fence));
if (!fence)
return;
pipe_reference_init(&fence->ref, 1);
if (deferred)
fence->unflushed_ctx = ctx;
for (unsigned b = 0; b < ice->batch_count; b++) {
struct crocus_batch *batch = &ice->batches[b];
if (deferred && crocus_batch_bytes_used(batch) > 0) {
struct crocus_fine_fence *fine =
crocus_fine_fence_new(batch, CROCUS_FENCE_BOTTOM_OF_PIPE);
crocus_fine_fence_reference(screen, &fence->fine[b], fine);
crocus_fine_fence_reference(screen, &fine, NULL);
} else {
/* This batch has no commands queued up (perhaps we just flushed,
* or all the commands are on the other batch). Wait for the last
* syncobj on this engine - unless it's already finished by now.
*/
if (crocus_fine_fence_signaled(batch->last_fence))
continue;
crocus_fine_fence_reference(screen, &fence->fine[b],
batch->last_fence);
}
}
crocus_fence_reference(ctx->screen, out_fence, NULL);
*out_fence = fence;
}
static void
crocus_fence_await(struct pipe_context *ctx, struct pipe_fence_handle *fence, uint64_t value)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
assert(!value);
/* Unflushed fences from the same context are no-ops. */
if (ctx && ctx == fence->unflushed_ctx)
return;
for (unsigned i = 0; i < ARRAY_SIZE(fence->fine); i++) {
struct crocus_fine_fence *fine = fence->fine[i];
if (crocus_fine_fence_signaled(fine))
continue;
for (unsigned b = 0; b < ice->batch_count; b++) {
struct crocus_batch *batch = &ice->batches[b];
/* We're going to make any future work in this batch wait for our
* fence to have gone by. But any currently queued work doesn't
* need to wait. Flush the batch now, so it can happen sooner.
*/
crocus_batch_flush(batch);
/* Before adding a new reference, clean out any stale ones. */
clear_stale_syncobjs(batch);
crocus_batch_add_syncobj(batch, fine->syncobj, I915_EXEC_FENCE_WAIT);
}
}
}
#define NSEC_PER_SEC (1000 * USEC_PER_SEC)
#define USEC_PER_SEC (1000 * MSEC_PER_SEC)
#define MSEC_PER_SEC (1000)
static uint64_t
gettime_ns(void)
{
struct timespec current;
clock_gettime(CLOCK_MONOTONIC, &current);
return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
}
static uint64_t
rel2abs(uint64_t timeout)
{
if (timeout == 0)
return 0;
uint64_t current_time = gettime_ns();
uint64_t max_timeout = (uint64_t)INT64_MAX - current_time;
timeout = MIN2(max_timeout, timeout);
return current_time + timeout;
}
static bool
crocus_fence_finish(struct pipe_screen *p_screen, struct pipe_context *ctx,
struct pipe_fence_handle *fence, uint64_t timeout)
{
ctx = threaded_context_unwrap_sync(ctx);
struct crocus_context *ice = (struct crocus_context *)ctx;
struct crocus_screen *screen = (struct crocus_screen *)p_screen;
/* If we created the fence with PIPE_FLUSH_DEFERRED, we may not have
* flushed yet. Check if our syncobj is the current batch's signalling
* syncobj - if so, we haven't flushed and need to now.
*
* The Gallium docs mention that a flush will occur if \p ctx matches
* the context the fence was created with. It may be NULL, so we check
* that it matches first.
*/
if (ctx && ctx == fence->unflushed_ctx) {
for (unsigned i = 0; i < ice->batch_count; i++) {
struct crocus_fine_fence *fine = fence->fine[i];
if (crocus_fine_fence_signaled(fine))
continue;
if (fine->syncobj == crocus_batch_get_signal_syncobj(&ice->batches[i]))
crocus_batch_flush(&ice->batches[i]);
}
/* The fence is no longer deferred. */
fence->unflushed_ctx = NULL;
}
unsigned int handle_count = 0;
uint32_t handles[ARRAY_SIZE(fence->fine)];
for (unsigned i = 0; i < ARRAY_SIZE(fence->fine); i++) {
struct crocus_fine_fence *fine = fence->fine[i];
if (crocus_fine_fence_signaled(fine))
continue;
handles[handle_count++] = fine->syncobj->handle;
}
if (handle_count == 0)
return true;
struct drm_syncobj_wait args = {
.handles = (uintptr_t)handles,
.count_handles = handle_count,
.timeout_nsec = rel2abs(timeout),
.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
};
if (fence->unflushed_ctx) {
/* This fence had a deferred flush from another context. We can't
* safely flush it here, because the context might be bound to a
* different thread, and poking at its internals wouldn't be safe.
*
* Instead, use the WAIT_FOR_SUBMIT flag to block and hope that
* another thread submits the work.
*/
args.flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
}
return intel_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args) == 0;
}
#ifndef SYNC_IOC_MAGIC
/* duplicated from linux/sync_file.h to avoid build-time dependency
* on new (v4.7) kernel headers. Once distro's are mostly using
* something newer than v4.7 drop this and #include <linux/sync_file.h>
* instead.
*/
struct sync_merge_data {
char name[32];
__s32 fd2;
__s32 fence;
__u32 flags;
__u32 pad;
};
#define SYNC_IOC_MAGIC '>'
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
#endif
static int
sync_merge_fd(int sync_fd, int new_fd)
{
if (sync_fd == -1)
return new_fd;
if (new_fd == -1)
return sync_fd;
struct sync_merge_data args = {
.name = "crocus fence",
.fd2 = new_fd,
.fence = -1,
};
intel_ioctl(sync_fd, SYNC_IOC_MERGE, &args);
close(new_fd);
close(sync_fd);
return args.fence;
}
static int
crocus_fence_get_fd(struct pipe_screen *p_screen,
struct pipe_fence_handle *fence)
{
struct crocus_screen *screen = (struct crocus_screen *)p_screen;
int fd = -1;
/* Deferred fences aren't supported. */
if (fence->unflushed_ctx)
return -1;
for (unsigned i = 0; i < ARRAY_SIZE(fence->fine); i++) {
struct crocus_fine_fence *fine = fence->fine[i];
if (crocus_fine_fence_signaled(fine))
continue;
struct drm_syncobj_handle args = {
.handle = fine->syncobj->handle,
.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
.fd = -1,
};
intel_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
fd = sync_merge_fd(fd, args.fd);
}
if (fd == -1) {
/* Our fence has no syncobj's recorded. This means that all of the
* batches had already completed, their syncobj's had been signalled,
* and so we didn't bother to record them. But we're being asked to
* export such a fence. So export a dummy already-signalled syncobj.
*/
struct drm_syncobj_handle args = {
.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
.fd = -1,
};
args.handle = gem_syncobj_create(screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED);
intel_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
gem_syncobj_destroy(screen->fd, args.handle);
return args.fd;
}
return fd;
}
static void
crocus_fence_create_fd(struct pipe_context *ctx, struct pipe_fence_handle **out,
int fd, enum pipe_fd_type type)
{
assert(type == PIPE_FD_TYPE_NATIVE_SYNC || type == PIPE_FD_TYPE_SYNCOBJ);
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
struct drm_syncobj_handle args = {
.fd = fd,
};
if (type == PIPE_FD_TYPE_NATIVE_SYNC) {
args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
args.handle = gem_syncobj_create(screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED);
}
if (intel_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args) == -1) {
fprintf(stderr, "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE failed: %s\n",
strerror(errno));
if (type == PIPE_FD_TYPE_NATIVE_SYNC)
gem_syncobj_destroy(screen->fd, args.handle);
*out = NULL;
return;
}
struct crocus_syncobj *syncobj = malloc(sizeof(*syncobj));
if (!syncobj) {
*out = NULL;
return;
}
syncobj->handle = args.handle;
pipe_reference_init(&syncobj->ref, 1);
struct crocus_fine_fence *fine = calloc(1, sizeof(*fine));
if (!fine) {
free(syncobj);
*out = NULL;
return;
}
static const uint32_t zero = 0;
/* Fences work in terms of crocus_fine_fence, but we don't actually have a
* seqno for an imported fence. So, create a fake one which always
* returns as 'not signaled' so we fall back to using the sync object.
*/
fine->seqno = UINT32_MAX;
fine->map = &zero;
fine->syncobj = syncobj;
fine->flags = CROCUS_FENCE_END;
pipe_reference_init(&fine->reference, 1);
struct pipe_fence_handle *fence = calloc(1, sizeof(*fence));
if (!fence) {
free(fine);
free(syncobj);
*out = NULL;
return;
}
pipe_reference_init(&fence->ref, 1);
fence->fine[0] = fine;
*out = fence;
}
static void
crocus_fence_signal(struct pipe_context *ctx, struct pipe_fence_handle *fence, uint64_t value)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
assert(!value);
if (ctx == fence->unflushed_ctx)
return;
for (unsigned b = 0; b < ice->batch_count; b++) {
for (unsigned i = 0; i < ARRAY_SIZE(fence->fine); i++) {
struct crocus_fine_fence *fine = fence->fine[i];
/* already signaled fence skipped */
if (crocus_fine_fence_signaled(fine))
continue;
ice->batches[b].contains_fence_signal = true;
crocus_batch_add_syncobj(&ice->batches[b], fine->syncobj,
I915_EXEC_FENCE_SIGNAL);
}
if (ice->batches[b].contains_fence_signal)
crocus_batch_flush(&ice->batches[b]);
}
}
void
crocus_init_screen_fence_functions(struct pipe_screen *screen)
{
screen->fence_reference = crocus_fence_reference;
screen->fence_finish = crocus_fence_finish;
screen->fence_get_fd = crocus_fence_get_fd;
}
void
crocus_init_context_fence_functions(struct pipe_context *ctx)
{
ctx->flush = crocus_fence_flush;
ctx->create_fence_fd = crocus_fence_create_fd;
ctx->fence_server_sync = crocus_fence_await;
ctx->fence_server_signal = crocus_fence_signal;
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef CROCUS_FENCE_H
#define CROCUS_FENCE_H
#include "util/u_inlines.h"
struct pipe_screen;
struct crocus_screen;
struct crocus_batch;
struct crocus_syncobj {
struct pipe_reference ref;
uint32_t handle;
};
void crocus_init_context_fence_functions(struct pipe_context *ctx);
void crocus_init_screen_fence_functions(struct pipe_screen *screen);
struct crocus_syncobj *crocus_create_syncobj(struct crocus_screen *screen);
void crocus_syncobj_destroy(struct crocus_screen *, struct crocus_syncobj *);
void crocus_batch_add_syncobj(struct crocus_batch *batch,
struct crocus_syncobj *syncobj,
unsigned flags);
bool crocus_wait_syncobj(struct pipe_screen *screen,
struct crocus_syncobj *syncobj,
int64_t timeout_nsec);
static inline void
crocus_syncobj_reference(struct crocus_screen *screen,
struct crocus_syncobj **dst,
struct crocus_syncobj *src)
{
if (pipe_reference(&(*dst)->ref, &src->ref))
crocus_syncobj_destroy(screen, *dst);
*dst = src;
}
#endif
@@ -0,0 +1,85 @@
#include "crocus_context.h"
#include "crocus_fine_fence.h"
#include "util/u_upload_mgr.h"
static void
crocus_fine_fence_reset(struct crocus_batch *batch)
{
u_upload_alloc_ref(batch->fine_fences.uploader,
0, sizeof(uint64_t), sizeof(uint64_t),
&batch->fine_fences.ref.offset, &batch->fine_fences.ref.res,
(void **)&batch->fine_fences.map);
WRITE_ONCE(*batch->fine_fences.map, 0);
batch->fine_fences.next++;
}
void
crocus_fine_fence_init(struct crocus_batch *batch)
{
batch->fine_fences.ref.res = NULL;
batch->fine_fences.next = 0;
if (batch_has_fine_fence(batch))
crocus_fine_fence_reset(batch);
}
static uint32_t
crocus_fine_fence_next(struct crocus_batch *batch)
{
if (!batch_has_fine_fence(batch))
return UINT32_MAX;
uint32_t seqno = batch->fine_fences.next++;
if (batch->fine_fences.next == 0)
crocus_fine_fence_reset(batch);
return seqno;
}
void
crocus_fine_fence_destroy(struct crocus_screen *screen,
struct crocus_fine_fence *fine)
{
crocus_syncobj_reference(screen, &fine->syncobj, NULL);
pipe_resource_reference(&fine->ref.res, NULL);
free(fine);
}
struct crocus_fine_fence *
crocus_fine_fence_new(struct crocus_batch *batch, unsigned flags)
{
struct crocus_fine_fence *fine = calloc(1, sizeof(*fine));
if (!fine)
return NULL;
pipe_reference_init(&fine->reference, 1);
fine->seqno = crocus_fine_fence_next(batch);
crocus_syncobj_reference(batch->screen, &fine->syncobj,
crocus_batch_get_signal_syncobj(batch));
if (!batch_has_fine_fence(batch))
return fine;
pipe_resource_reference(&fine->ref.res, batch->fine_fences.ref.res);
fine->ref.offset = batch->fine_fences.ref.offset;
fine->map = batch->fine_fences.map;
fine->flags = flags;
unsigned pc;
if (flags & CROCUS_FENCE_TOP_OF_PIPE) {
pc = PIPE_CONTROL_WRITE_IMMEDIATE | PIPE_CONTROL_CS_STALL;
} else {
pc = PIPE_CONTROL_WRITE_IMMEDIATE |
PIPE_CONTROL_RENDER_TARGET_FLUSH |
PIPE_CONTROL_TILE_CACHE_FLUSH |
PIPE_CONTROL_DEPTH_CACHE_FLUSH |
PIPE_CONTROL_DATA_CACHE_FLUSH;
}
crocus_emit_pipe_control_write(batch, "fence: fine", pc,
crocus_resource_bo(fine->ref.res),
fine->ref.offset,
fine->seqno);
return fine;
}
@@ -0,0 +1,109 @@
/*
* Copyright © 2020 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef CROCUS_FINE_FENCE_DOT_H
#define CROCUS_FINE_FENCE_DOT_H
#include <stdbool.h>
#include <stdint.h>
#include "crocus_screen.h"
#include "crocus_resource.h"
/**
* A lightweight sequence number fence.
*
* We emit PIPE_CONTROLs inside a batch (possibly in the middle)
* which update a monotonically increasing, 32-bit counter. We
* can then check if that moment has passed by either:
*
* 1. Checking on the CPU by snooping on the DWord via a coherent map
*
* 2. Blocking on the GPU with MI_SEMAPHORE_WAIT from a second batch
* (relying on mid-batch preemption to switch GPU execution to the
* batch that writes it).
*/
struct crocus_fine_fence {
struct pipe_reference reference;
/** Buffer where the seqno lives */
struct crocus_state_ref ref;
/** Coherent CPU map of the buffer containing the seqno DWord. */
const uint32_t *map;
/**
* A drm_syncobj pointing which will be signaled at the end of the
* batch which writes this seqno. This can be used to block until
* the seqno has definitely passed (but may wait longer than necessary).
*/
struct crocus_syncobj *syncobj;
#define CROCUS_FENCE_BOTTOM_OF_PIPE 0x0 /**< Written by bottom-of-pipe flush */
#define CROCUS_FENCE_TOP_OF_PIPE 0x1 /**< Written by top-of-pipe flush */
#define CROCUS_FENCE_END 0x2 /**< Written at the end of a batch */
/** Information about the type of flush involved (see CROCUS_FENCE_*) */
uint32_t flags;
/**
* Sequence number expected to be written by the flush we inserted
* when creating this fence. The crocus_fine_fence is 'signaled' when *@map
* (written by the flush on the GPU) is greater-than-or-equal to @seqno.
*/
uint32_t seqno;
};
void crocus_fine_fence_init(struct crocus_batch *batch);
struct crocus_fine_fence *crocus_fine_fence_new(struct crocus_batch *batch,
unsigned flags);
void crocus_fine_fence_destroy(struct crocus_screen *screen,
struct crocus_fine_fence *sq);
static inline void
crocus_fine_fence_reference(struct crocus_screen *screen,
struct crocus_fine_fence **dst,
struct crocus_fine_fence *src)
{
if (pipe_reference(&(*dst)->reference, &src->reference))
crocus_fine_fence_destroy(screen, *dst);
*dst = src;
}
/**
* Return true if this seqno has passed.
*
* NULL is considered signaled.
*/
static inline bool
crocus_fine_fence_signaled(const struct crocus_fine_fence *sq)
{
if (sq && !sq->map)
return false;
return !sq || (READ_ONCE(*sq->map) >= sq->seqno);
}
#endif
+585
View File
@@ -0,0 +1,585 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_formats.c
*
* Converts Gallium formats (PIPE_FORMAT_*) to hardware ones (ISL_FORMAT_*).
* Provides information about which formats support what features.
*/
#include "util/bitscan.h"
#include "util/macros.h"
#include "util/format/u_format.h"
#include "crocus_resource.h"
#include "crocus_screen.h"
static enum isl_format
crocus_isl_format_for_pipe_format(enum pipe_format pf)
{
static const enum isl_format table[PIPE_FORMAT_COUNT] = {
[0 ... PIPE_FORMAT_COUNT-1] = ISL_FORMAT_UNSUPPORTED,
[PIPE_FORMAT_B8G8R8A8_UNORM] = ISL_FORMAT_B8G8R8A8_UNORM,
[PIPE_FORMAT_B8G8R8X8_UNORM] = ISL_FORMAT_B8G8R8X8_UNORM,
[PIPE_FORMAT_B5G5R5A1_UNORM] = ISL_FORMAT_B5G5R5A1_UNORM,
[PIPE_FORMAT_B4G4R4A4_UNORM] = ISL_FORMAT_B4G4R4A4_UNORM,
[PIPE_FORMAT_B5G6R5_UNORM] = ISL_FORMAT_B5G6R5_UNORM,
[PIPE_FORMAT_R10G10B10A2_UNORM] = ISL_FORMAT_R10G10B10A2_UNORM,
[PIPE_FORMAT_Z16_UNORM] = ISL_FORMAT_R16_UNORM,
[PIPE_FORMAT_Z32_UNORM] = ISL_FORMAT_R32_UNORM,
[PIPE_FORMAT_Z32_FLOAT] = ISL_FORMAT_R32_FLOAT,
/* We translate the combined depth/stencil formats to depth only here */
[PIPE_FORMAT_Z24_UNORM_S8_UINT] = ISL_FORMAT_R24_UNORM_X8_TYPELESS,
[PIPE_FORMAT_Z24X8_UNORM] = ISL_FORMAT_R24_UNORM_X8_TYPELESS,
[PIPE_FORMAT_Z32_FLOAT_S8X24_UINT] = ISL_FORMAT_R32_FLOAT,
[PIPE_FORMAT_S8_UINT] = ISL_FORMAT_R8_UINT,
[PIPE_FORMAT_X24S8_UINT] = ISL_FORMAT_R8_UINT,
[PIPE_FORMAT_X32_S8X24_UINT] = ISL_FORMAT_R8_UINT,
[PIPE_FORMAT_R64_FLOAT] = ISL_FORMAT_R64_FLOAT,
[PIPE_FORMAT_R64G64_FLOAT] = ISL_FORMAT_R64G64_FLOAT,
[PIPE_FORMAT_R64G64B64_FLOAT] = ISL_FORMAT_R64G64B64_FLOAT,
[PIPE_FORMAT_R64G64B64A64_FLOAT] = ISL_FORMAT_R64G64B64A64_FLOAT,
[PIPE_FORMAT_R32_FLOAT] = ISL_FORMAT_R32_FLOAT,
[PIPE_FORMAT_R32G32_FLOAT] = ISL_FORMAT_R32G32_FLOAT,
[PIPE_FORMAT_R32G32B32_FLOAT] = ISL_FORMAT_R32G32B32_FLOAT,
[PIPE_FORMAT_R32G32B32A32_FLOAT] = ISL_FORMAT_R32G32B32A32_FLOAT,
[PIPE_FORMAT_R32_UNORM] = ISL_FORMAT_R32_UNORM,
[PIPE_FORMAT_R32G32_UNORM] = ISL_FORMAT_R32G32_UNORM,
[PIPE_FORMAT_R32G32B32_UNORM] = ISL_FORMAT_R32G32B32_UNORM,
[PIPE_FORMAT_R32G32B32A32_UNORM] = ISL_FORMAT_R32G32B32A32_UNORM,
[PIPE_FORMAT_R32_USCALED] = ISL_FORMAT_R32_USCALED,
[PIPE_FORMAT_R32G32_USCALED] = ISL_FORMAT_R32G32_USCALED,
[PIPE_FORMAT_R32G32B32_USCALED] = ISL_FORMAT_R32G32B32_USCALED,
[PIPE_FORMAT_R32G32B32A32_USCALED] = ISL_FORMAT_R32G32B32A32_USCALED,
[PIPE_FORMAT_R32_SNORM] = ISL_FORMAT_R32_SNORM,
[PIPE_FORMAT_R32G32_SNORM] = ISL_FORMAT_R32G32_SNORM,
[PIPE_FORMAT_R32G32B32_SNORM] = ISL_FORMAT_R32G32B32_SNORM,
[PIPE_FORMAT_R32G32B32A32_SNORM] = ISL_FORMAT_R32G32B32A32_SNORM,
[PIPE_FORMAT_R32_SSCALED] = ISL_FORMAT_R32_SSCALED,
[PIPE_FORMAT_R32G32_SSCALED] = ISL_FORMAT_R32G32_SSCALED,
[PIPE_FORMAT_R32G32B32_SSCALED] = ISL_FORMAT_R32G32B32_SSCALED,
[PIPE_FORMAT_R32G32B32A32_SSCALED] = ISL_FORMAT_R32G32B32A32_SSCALED,
[PIPE_FORMAT_R16_UNORM] = ISL_FORMAT_R16_UNORM,
[PIPE_FORMAT_R16G16_UNORM] = ISL_FORMAT_R16G16_UNORM,
[PIPE_FORMAT_R16G16B16_UNORM] = ISL_FORMAT_R16G16B16_UNORM,
[PIPE_FORMAT_R16G16B16A16_UNORM] = ISL_FORMAT_R16G16B16A16_UNORM,
[PIPE_FORMAT_R16_USCALED] = ISL_FORMAT_R16_USCALED,
[PIPE_FORMAT_R16G16_USCALED] = ISL_FORMAT_R16G16_USCALED,
[PIPE_FORMAT_R16G16B16_USCALED] = ISL_FORMAT_R16G16B16_USCALED,
[PIPE_FORMAT_R16G16B16A16_USCALED] = ISL_FORMAT_R16G16B16A16_USCALED,
[PIPE_FORMAT_R16_SNORM] = ISL_FORMAT_R16_SNORM,
[PIPE_FORMAT_R16G16_SNORM] = ISL_FORMAT_R16G16_SNORM,
[PIPE_FORMAT_R16G16B16_SNORM] = ISL_FORMAT_R16G16B16_SNORM,
[PIPE_FORMAT_R16G16B16A16_SNORM] = ISL_FORMAT_R16G16B16A16_SNORM,
[PIPE_FORMAT_R16_SSCALED] = ISL_FORMAT_R16_SSCALED,
[PIPE_FORMAT_R16G16_SSCALED] = ISL_FORMAT_R16G16_SSCALED,
[PIPE_FORMAT_R16G16B16_SSCALED] = ISL_FORMAT_R16G16B16_SSCALED,
[PIPE_FORMAT_R16G16B16A16_SSCALED] = ISL_FORMAT_R16G16B16A16_SSCALED,
[PIPE_FORMAT_R8_UNORM] = ISL_FORMAT_R8_UNORM,
[PIPE_FORMAT_R8G8_UNORM] = ISL_FORMAT_R8G8_UNORM,
[PIPE_FORMAT_R8G8B8_UNORM] = ISL_FORMAT_R8G8B8_UNORM,
[PIPE_FORMAT_R8G8B8A8_UNORM] = ISL_FORMAT_R8G8B8A8_UNORM,
[PIPE_FORMAT_R8_USCALED] = ISL_FORMAT_R8_USCALED,
[PIPE_FORMAT_R8G8_USCALED] = ISL_FORMAT_R8G8_USCALED,
[PIPE_FORMAT_R8G8B8_USCALED] = ISL_FORMAT_R8G8B8_USCALED,
[PIPE_FORMAT_R8G8B8A8_USCALED] = ISL_FORMAT_R8G8B8A8_USCALED,
[PIPE_FORMAT_R8_SNORM] = ISL_FORMAT_R8_SNORM,
[PIPE_FORMAT_R8G8_SNORM] = ISL_FORMAT_R8G8_SNORM,
[PIPE_FORMAT_R8G8B8_SNORM] = ISL_FORMAT_R8G8B8_SNORM,
[PIPE_FORMAT_R8G8B8A8_SNORM] = ISL_FORMAT_R8G8B8A8_SNORM,
[PIPE_FORMAT_R8_SSCALED] = ISL_FORMAT_R8_SSCALED,
[PIPE_FORMAT_R8G8_SSCALED] = ISL_FORMAT_R8G8_SSCALED,
[PIPE_FORMAT_R8G8B8_SSCALED] = ISL_FORMAT_R8G8B8_SSCALED,
[PIPE_FORMAT_R8G8B8A8_SSCALED] = ISL_FORMAT_R8G8B8A8_SSCALED,
[PIPE_FORMAT_R32_FIXED] = ISL_FORMAT_R32_SFIXED,
[PIPE_FORMAT_R32G32_FIXED] = ISL_FORMAT_R32G32_SFIXED,
[PIPE_FORMAT_R32G32B32_FIXED] = ISL_FORMAT_R32G32B32_SFIXED,
[PIPE_FORMAT_R32G32B32A32_FIXED] = ISL_FORMAT_R32G32B32A32_SFIXED,
[PIPE_FORMAT_R16_FLOAT] = ISL_FORMAT_R16_FLOAT,
[PIPE_FORMAT_R16G16_FLOAT] = ISL_FORMAT_R16G16_FLOAT,
[PIPE_FORMAT_R16G16B16_FLOAT] = ISL_FORMAT_R16G16B16_FLOAT,
[PIPE_FORMAT_R16G16B16A16_FLOAT] = ISL_FORMAT_R16G16B16A16_FLOAT,
[PIPE_FORMAT_R8G8B8_SRGB] = ISL_FORMAT_R8G8B8_UNORM_SRGB,
[PIPE_FORMAT_B8G8R8A8_SRGB] = ISL_FORMAT_B8G8R8A8_UNORM_SRGB,
[PIPE_FORMAT_B8G8R8X8_SRGB] = ISL_FORMAT_B8G8R8X8_UNORM_SRGB,
[PIPE_FORMAT_R8G8B8A8_SRGB] = ISL_FORMAT_R8G8B8A8_UNORM_SRGB,
[PIPE_FORMAT_DXT1_RGB] = ISL_FORMAT_BC1_UNORM,
[PIPE_FORMAT_DXT1_RGBA] = ISL_FORMAT_BC1_UNORM,
[PIPE_FORMAT_DXT3_RGBA] = ISL_FORMAT_BC2_UNORM,
[PIPE_FORMAT_DXT5_RGBA] = ISL_FORMAT_BC3_UNORM,
[PIPE_FORMAT_DXT1_SRGB] = ISL_FORMAT_BC1_UNORM_SRGB,
[PIPE_FORMAT_DXT1_SRGBA] = ISL_FORMAT_BC1_UNORM_SRGB,
[PIPE_FORMAT_DXT3_SRGBA] = ISL_FORMAT_BC2_UNORM_SRGB,
[PIPE_FORMAT_DXT5_SRGBA] = ISL_FORMAT_BC3_UNORM_SRGB,
[PIPE_FORMAT_RGTC1_UNORM] = ISL_FORMAT_BC4_UNORM,
[PIPE_FORMAT_RGTC1_SNORM] = ISL_FORMAT_BC4_SNORM,
[PIPE_FORMAT_RGTC2_UNORM] = ISL_FORMAT_BC5_UNORM,
[PIPE_FORMAT_RGTC2_SNORM] = ISL_FORMAT_BC5_SNORM,
[PIPE_FORMAT_R10G10B10A2_USCALED] = ISL_FORMAT_R10G10B10A2_USCALED,
[PIPE_FORMAT_R11G11B10_FLOAT] = ISL_FORMAT_R11G11B10_FLOAT,
[PIPE_FORMAT_R9G9B9E5_FLOAT] = ISL_FORMAT_R9G9B9E5_SHAREDEXP,
[PIPE_FORMAT_R1_UNORM] = ISL_FORMAT_R1_UNORM,
[PIPE_FORMAT_R10G10B10X2_USCALED] = ISL_FORMAT_R10G10B10X2_USCALED,
[PIPE_FORMAT_B10G10R10A2_UNORM] = ISL_FORMAT_B10G10R10A2_UNORM,
[PIPE_FORMAT_R8G8B8X8_UNORM] = ISL_FORMAT_R8G8B8X8_UNORM,
[PIPE_FORMAT_I8_UNORM] = ISL_FORMAT_R8_UNORM,
[PIPE_FORMAT_I16_UNORM] = ISL_FORMAT_R16_UNORM,
[PIPE_FORMAT_I8_SNORM] = ISL_FORMAT_R8_SNORM,
[PIPE_FORMAT_I16_SNORM] = ISL_FORMAT_R16_SNORM,
[PIPE_FORMAT_I16_FLOAT] = ISL_FORMAT_R16_FLOAT,
[PIPE_FORMAT_I32_FLOAT] = ISL_FORMAT_R32_FLOAT,
[PIPE_FORMAT_L8_UINT] = ISL_FORMAT_L8_UINT,
[PIPE_FORMAT_L8_UNORM] = ISL_FORMAT_L8_UNORM,
[PIPE_FORMAT_L8_SNORM] = ISL_FORMAT_R8_SNORM,
[PIPE_FORMAT_L8_SINT] = ISL_FORMAT_L8_SINT,
[PIPE_FORMAT_L16_UNORM] = ISL_FORMAT_L16_UNORM,
[PIPE_FORMAT_L16_SNORM] = ISL_FORMAT_R16_SNORM,
[PIPE_FORMAT_L16_FLOAT] = ISL_FORMAT_L16_FLOAT,
[PIPE_FORMAT_L32_FLOAT] = ISL_FORMAT_L32_FLOAT,
[PIPE_FORMAT_A8_UNORM] = ISL_FORMAT_A8_UNORM,
[PIPE_FORMAT_A16_UNORM] = ISL_FORMAT_A16_UNORM,
[PIPE_FORMAT_A16_FLOAT] = ISL_FORMAT_A16_FLOAT,
[PIPE_FORMAT_A32_FLOAT] = ISL_FORMAT_A32_FLOAT,
[PIPE_FORMAT_L8A8_UNORM] = ISL_FORMAT_L8A8_UNORM,
[PIPE_FORMAT_L16A16_UNORM] = ISL_FORMAT_L16A16_UNORM,
[PIPE_FORMAT_L16A16_FLOAT] = ISL_FORMAT_L16A16_FLOAT,
[PIPE_FORMAT_L32A32_FLOAT] = ISL_FORMAT_L32A32_FLOAT,
/* Sadly, we have to use luminance[-alpha] formats for sRGB decoding. */
[PIPE_FORMAT_R8_SRGB] = ISL_FORMAT_L8_UNORM_SRGB,
[PIPE_FORMAT_L8_SRGB] = ISL_FORMAT_L8_UNORM_SRGB,
[PIPE_FORMAT_L8A8_SRGB] = ISL_FORMAT_L8A8_UNORM_SRGB,
[PIPE_FORMAT_R10G10B10A2_SSCALED] = ISL_FORMAT_R10G10B10A2_SSCALED,
[PIPE_FORMAT_R10G10B10A2_SNORM] = ISL_FORMAT_R10G10B10A2_SNORM,
[PIPE_FORMAT_B10G10R10A2_USCALED] = ISL_FORMAT_B10G10R10A2_USCALED,
[PIPE_FORMAT_B10G10R10A2_SSCALED] = ISL_FORMAT_B10G10R10A2_SSCALED,
[PIPE_FORMAT_B10G10R10A2_SNORM] = ISL_FORMAT_B10G10R10A2_SNORM,
[PIPE_FORMAT_R8_UINT] = ISL_FORMAT_R8_UINT,
[PIPE_FORMAT_R8G8_UINT] = ISL_FORMAT_R8G8_UINT,
[PIPE_FORMAT_R8G8B8_UINT] = ISL_FORMAT_R8G8B8_UINT,
[PIPE_FORMAT_R8G8B8A8_UINT] = ISL_FORMAT_R8G8B8A8_UINT,
[PIPE_FORMAT_R8_SINT] = ISL_FORMAT_R8_SINT,
[PIPE_FORMAT_R8G8_SINT] = ISL_FORMAT_R8G8_SINT,
[PIPE_FORMAT_R8G8B8_SINT] = ISL_FORMAT_R8G8B8_SINT,
[PIPE_FORMAT_R8G8B8A8_SINT] = ISL_FORMAT_R8G8B8A8_SINT,
[PIPE_FORMAT_R16_UINT] = ISL_FORMAT_R16_UINT,
[PIPE_FORMAT_R16G16_UINT] = ISL_FORMAT_R16G16_UINT,
[PIPE_FORMAT_R16G16B16_UINT] = ISL_FORMAT_R16G16B16_UINT,
[PIPE_FORMAT_R16G16B16A16_UINT] = ISL_FORMAT_R16G16B16A16_UINT,
[PIPE_FORMAT_R16_SINT] = ISL_FORMAT_R16_SINT,
[PIPE_FORMAT_R16G16_SINT] = ISL_FORMAT_R16G16_SINT,
[PIPE_FORMAT_R16G16B16_SINT] = ISL_FORMAT_R16G16B16_SINT,
[PIPE_FORMAT_R16G16B16A16_SINT] = ISL_FORMAT_R16G16B16A16_SINT,
[PIPE_FORMAT_R32_UINT] = ISL_FORMAT_R32_UINT,
[PIPE_FORMAT_R32G32_UINT] = ISL_FORMAT_R32G32_UINT,
[PIPE_FORMAT_R32G32B32_UINT] = ISL_FORMAT_R32G32B32_UINT,
[PIPE_FORMAT_R32G32B32A32_UINT] = ISL_FORMAT_R32G32B32A32_UINT,
[PIPE_FORMAT_R32_SINT] = ISL_FORMAT_R32_SINT,
[PIPE_FORMAT_R32G32_SINT] = ISL_FORMAT_R32G32_SINT,
[PIPE_FORMAT_R32G32B32_SINT] = ISL_FORMAT_R32G32B32_SINT,
[PIPE_FORMAT_R32G32B32A32_SINT] = ISL_FORMAT_R32G32B32A32_SINT,
[PIPE_FORMAT_B10G10R10A2_UINT] = ISL_FORMAT_B10G10R10A2_UINT,
[PIPE_FORMAT_ETC1_RGB8] = ISL_FORMAT_ETC1_RGB8,
[PIPE_FORMAT_R8G8B8X8_SRGB] = ISL_FORMAT_R8G8B8X8_UNORM_SRGB,
[PIPE_FORMAT_B10G10R10X2_UNORM] = ISL_FORMAT_B10G10R10X2_UNORM,
[PIPE_FORMAT_R16G16B16X16_UNORM] = ISL_FORMAT_R16G16B16X16_UNORM,
[PIPE_FORMAT_R16G16B16X16_FLOAT] = ISL_FORMAT_R16G16B16X16_FLOAT,
[PIPE_FORMAT_R32G32B32X32_FLOAT] = ISL_FORMAT_R32G32B32X32_FLOAT,
[PIPE_FORMAT_R10G10B10A2_UINT] = ISL_FORMAT_R10G10B10A2_UINT,
[PIPE_FORMAT_B5G6R5_SRGB] = ISL_FORMAT_B5G6R5_UNORM_SRGB,
[PIPE_FORMAT_BPTC_RGBA_UNORM] = ISL_FORMAT_BC7_UNORM,
[PIPE_FORMAT_BPTC_SRGBA] = ISL_FORMAT_BC7_UNORM_SRGB,
[PIPE_FORMAT_BPTC_RGB_FLOAT] = ISL_FORMAT_BC6H_SF16,
[PIPE_FORMAT_BPTC_RGB_UFLOAT] = ISL_FORMAT_BC6H_UF16,
[PIPE_FORMAT_ETC2_RGB8] = ISL_FORMAT_ETC2_RGB8,
[PIPE_FORMAT_ETC2_SRGB8] = ISL_FORMAT_ETC2_SRGB8,
[PIPE_FORMAT_ETC2_RGB8A1] = ISL_FORMAT_ETC2_RGB8_PTA,
[PIPE_FORMAT_ETC2_SRGB8A1] = ISL_FORMAT_ETC2_SRGB8_PTA,
[PIPE_FORMAT_ETC2_RGBA8] = ISL_FORMAT_ETC2_EAC_RGBA8,
[PIPE_FORMAT_ETC2_SRGBA8] = ISL_FORMAT_ETC2_EAC_SRGB8_A8,
[PIPE_FORMAT_ETC2_R11_UNORM] = ISL_FORMAT_EAC_R11,
[PIPE_FORMAT_ETC2_R11_SNORM] = ISL_FORMAT_EAC_SIGNED_R11,
[PIPE_FORMAT_ETC2_RG11_UNORM] = ISL_FORMAT_EAC_RG11,
[PIPE_FORMAT_ETC2_RG11_SNORM] = ISL_FORMAT_EAC_SIGNED_RG11,
[PIPE_FORMAT_FXT1_RGB] = ISL_FORMAT_FXT1,
[PIPE_FORMAT_FXT1_RGBA] = ISL_FORMAT_FXT1,
[PIPE_FORMAT_ASTC_4x4] = ISL_FORMAT_ASTC_LDR_2D_4X4_FLT16,
[PIPE_FORMAT_ASTC_5x4] = ISL_FORMAT_ASTC_LDR_2D_5X4_FLT16,
[PIPE_FORMAT_ASTC_5x5] = ISL_FORMAT_ASTC_LDR_2D_5X5_FLT16,
[PIPE_FORMAT_ASTC_6x5] = ISL_FORMAT_ASTC_LDR_2D_6X5_FLT16,
[PIPE_FORMAT_ASTC_6x6] = ISL_FORMAT_ASTC_LDR_2D_6X6_FLT16,
[PIPE_FORMAT_ASTC_8x5] = ISL_FORMAT_ASTC_LDR_2D_8X5_FLT16,
[PIPE_FORMAT_ASTC_8x6] = ISL_FORMAT_ASTC_LDR_2D_8X6_FLT16,
[PIPE_FORMAT_ASTC_8x8] = ISL_FORMAT_ASTC_LDR_2D_8X8_FLT16,
[PIPE_FORMAT_ASTC_10x5] = ISL_FORMAT_ASTC_LDR_2D_10X5_FLT16,
[PIPE_FORMAT_ASTC_10x6] = ISL_FORMAT_ASTC_LDR_2D_10X6_FLT16,
[PIPE_FORMAT_ASTC_10x8] = ISL_FORMAT_ASTC_LDR_2D_10X8_FLT16,
[PIPE_FORMAT_ASTC_10x10] = ISL_FORMAT_ASTC_LDR_2D_10X10_FLT16,
[PIPE_FORMAT_ASTC_12x10] = ISL_FORMAT_ASTC_LDR_2D_12X10_FLT16,
[PIPE_FORMAT_ASTC_12x12] = ISL_FORMAT_ASTC_LDR_2D_12X12_FLT16,
[PIPE_FORMAT_ASTC_4x4_SRGB] = ISL_FORMAT_ASTC_LDR_2D_4X4_U8SRGB,
[PIPE_FORMAT_ASTC_5x4_SRGB] = ISL_FORMAT_ASTC_LDR_2D_5X4_U8SRGB,
[PIPE_FORMAT_ASTC_5x5_SRGB] = ISL_FORMAT_ASTC_LDR_2D_5X5_U8SRGB,
[PIPE_FORMAT_ASTC_6x5_SRGB] = ISL_FORMAT_ASTC_LDR_2D_6X5_U8SRGB,
[PIPE_FORMAT_ASTC_6x6_SRGB] = ISL_FORMAT_ASTC_LDR_2D_6X6_U8SRGB,
[PIPE_FORMAT_ASTC_8x5_SRGB] = ISL_FORMAT_ASTC_LDR_2D_8X5_U8SRGB,
[PIPE_FORMAT_ASTC_8x6_SRGB] = ISL_FORMAT_ASTC_LDR_2D_8X6_U8SRGB,
[PIPE_FORMAT_ASTC_8x8_SRGB] = ISL_FORMAT_ASTC_LDR_2D_8X8_U8SRGB,
[PIPE_FORMAT_ASTC_10x5_SRGB] = ISL_FORMAT_ASTC_LDR_2D_10X5_U8SRGB,
[PIPE_FORMAT_ASTC_10x6_SRGB] = ISL_FORMAT_ASTC_LDR_2D_10X6_U8SRGB,
[PIPE_FORMAT_ASTC_10x8_SRGB] = ISL_FORMAT_ASTC_LDR_2D_10X8_U8SRGB,
[PIPE_FORMAT_ASTC_10x10_SRGB] = ISL_FORMAT_ASTC_LDR_2D_10X10_U8SRGB,
[PIPE_FORMAT_ASTC_12x10_SRGB] = ISL_FORMAT_ASTC_LDR_2D_12X10_U8SRGB,
[PIPE_FORMAT_ASTC_12x12_SRGB] = ISL_FORMAT_ASTC_LDR_2D_12X12_U8SRGB,
[PIPE_FORMAT_A1B5G5R5_UNORM] = ISL_FORMAT_A1B5G5R5_UNORM,
/* We support these so that we know the API expects no alpha channel.
* Otherwise, the state tracker would just give us a format with alpha
* and we wouldn't know to override the swizzle to 1.
*/
[PIPE_FORMAT_R16G16B16X16_UINT] = ISL_FORMAT_R16G16B16A16_UINT,
[PIPE_FORMAT_R16G16B16X16_SINT] = ISL_FORMAT_R16G16B16A16_SINT,
[PIPE_FORMAT_R32G32B32X32_UINT] = ISL_FORMAT_R32G32B32A32_UINT,
[PIPE_FORMAT_R32G32B32X32_SINT] = ISL_FORMAT_R32G32B32A32_SINT,
[PIPE_FORMAT_R10G10B10X2_SNORM] = ISL_FORMAT_R10G10B10A2_SNORM,
};
assert(pf < PIPE_FORMAT_COUNT);
return table[pf];
}
static enum isl_format
get_render_format(enum pipe_format pformat, enum isl_format def_format)
{
switch (pformat) {
case PIPE_FORMAT_A16_UNORM: return ISL_FORMAT_R16_UNORM;
case PIPE_FORMAT_A16_FLOAT: return ISL_FORMAT_R16_FLOAT;
case PIPE_FORMAT_A32_FLOAT: return ISL_FORMAT_R32_FLOAT;
case PIPE_FORMAT_I8_UNORM: return ISL_FORMAT_R8_UNORM;
case PIPE_FORMAT_I16_UNORM: return ISL_FORMAT_R16_UNORM;
case PIPE_FORMAT_I16_FLOAT: return ISL_FORMAT_R16_FLOAT;
case PIPE_FORMAT_I32_FLOAT: return ISL_FORMAT_R32_FLOAT;
case PIPE_FORMAT_L8_UNORM: return ISL_FORMAT_R8_UNORM;
case PIPE_FORMAT_L8_UINT: return ISL_FORMAT_R8_UINT;
case PIPE_FORMAT_L8_SINT: return ISL_FORMAT_R8_SINT;
case PIPE_FORMAT_L16_UNORM: return ISL_FORMAT_R16_UNORM;
case PIPE_FORMAT_L16_FLOAT: return ISL_FORMAT_R16_FLOAT;
case PIPE_FORMAT_L32_FLOAT: return ISL_FORMAT_R32_FLOAT;
case PIPE_FORMAT_L8A8_UNORM: return ISL_FORMAT_R8G8_UNORM;
case PIPE_FORMAT_L16A16_UNORM: return ISL_FORMAT_R16G16_UNORM;
case PIPE_FORMAT_L16A16_FLOAT: return ISL_FORMAT_R16G16_FLOAT;
case PIPE_FORMAT_L32A32_FLOAT: return ISL_FORMAT_R32G32_FLOAT;
default:
return def_format;
}
}
struct crocus_format_info
crocus_format_for_usage(const struct intel_device_info *devinfo,
enum pipe_format pformat,
isl_surf_usage_flags_t usage)
{
struct crocus_format_info info = { crocus_isl_format_for_pipe_format(pformat),
{ PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W } };
if (info.fmt == ISL_FORMAT_UNSUPPORTED)
return info;
if (pformat == PIPE_FORMAT_A8_UNORM) {
info.fmt = ISL_FORMAT_A8_UNORM;
}
if (usage & ISL_SURF_USAGE_RENDER_TARGET_BIT)
info.fmt = get_render_format(pformat, info.fmt);
if (devinfo->ver < 6) {
if (pformat == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)
info.fmt = ISL_FORMAT_R32_FLOAT_X8X24_TYPELESS;
if (pformat == PIPE_FORMAT_X32_S8X24_UINT)
info.fmt = ISL_FORMAT_X32_TYPELESS_G8X24_UINT;
if (pformat == PIPE_FORMAT_X24S8_UINT)
info.fmt = ISL_FORMAT_X24_TYPELESS_G8_UINT;
}
const struct isl_format_layout *fmtl = isl_format_get_layout(info.fmt);
if (util_format_is_snorm(pformat)) {
if (util_format_is_intensity(pformat)) {
info.swizzles[0] = PIPE_SWIZZLE_X;
info.swizzles[1] = PIPE_SWIZZLE_X;
info.swizzles[2] = PIPE_SWIZZLE_X;
info.swizzles[3] = PIPE_SWIZZLE_X;
} else if (util_format_is_luminance(pformat)) {
info.swizzles[0] = PIPE_SWIZZLE_X;
info.swizzles[1] = PIPE_SWIZZLE_X;
info.swizzles[2] = PIPE_SWIZZLE_X;
info.swizzles[3] = PIPE_SWIZZLE_1;
} else if (util_format_is_luminance_alpha(pformat)) {
info.swizzles[0] = PIPE_SWIZZLE_X;
info.swizzles[1] = PIPE_SWIZZLE_X;
info.swizzles[2] = PIPE_SWIZZLE_X;
info.swizzles[3] = PIPE_SWIZZLE_Y;
} else if (util_format_is_alpha(pformat)) {
info.swizzles[0] = PIPE_SWIZZLE_0;
info.swizzles[1] = PIPE_SWIZZLE_0;
info.swizzles[2] = PIPE_SWIZZLE_0;
info.swizzles[3] = PIPE_SWIZZLE_X;
}
}
/* When faking RGBX pipe formats with RGBA ISL formats, override alpha. */
if (!util_format_has_alpha(pformat) && fmtl->channels.a.type != ISL_VOID) {
info.swizzles[0] = PIPE_SWIZZLE_X;
info.swizzles[1] = PIPE_SWIZZLE_Y;
info.swizzles[2] = PIPE_SWIZZLE_Z;
info.swizzles[3] = PIPE_SWIZZLE_1;
}
/* We choose RGBA over RGBX for rendering the hardware doesn't support
* rendering to RGBX. However, when this internal override is used on Gen9+,
* fast clears don't work correctly.
*
* i965 fixes this by pretending to not support RGBX formats, and the higher
* layers of Mesa pick the RGBA format instead. Gallium doesn't work that
* way, and might choose a different format, like BGRX instead of RGBX,
* which will also cause problems when sampling from a surface fast cleared
* as RGBX. So we always choose RGBA instead of RGBX explicitly
* here.
*/
if (isl_format_is_rgbx(info.fmt) &&
!isl_format_supports_rendering(devinfo, info.fmt) &&
(usage & ISL_SURF_USAGE_RENDER_TARGET_BIT)) {
info.fmt = isl_format_rgbx_to_rgba(info.fmt);
info.swizzles[0] = PIPE_SWIZZLE_X;
info.swizzles[1] = PIPE_SWIZZLE_Y;
info.swizzles[2] = PIPE_SWIZZLE_Z;
info.swizzles[3] = PIPE_SWIZZLE_1;
}
return info;
}
/**
* The pscreen->is_format_supported() driver hook.
*
* Returns true if the given format is supported for the given usage
* (PIPE_BIND_*) and sample count.
*/
bool
crocus_is_format_supported(struct pipe_screen *pscreen,
enum pipe_format pformat,
enum pipe_texture_target target,
unsigned sample_count, unsigned storage_sample_count,
unsigned usage)
{
struct crocus_screen *screen = (struct crocus_screen *)pscreen;
const struct intel_device_info *devinfo = &screen->devinfo;
if (!util_is_power_of_two_or_zero(sample_count))
return false;
if (devinfo->ver >= 7) {
if (sample_count > 8 || sample_count == 2)
return false;
} else if (devinfo->ver == 6) {
if (sample_count > 4 || sample_count == 2)
return false;
} else if (sample_count > 1) {
return false;
}
if (pformat == PIPE_FORMAT_NONE)
return true;
enum isl_format format = crocus_isl_format_for_pipe_format(pformat);
if (format == ISL_FORMAT_UNSUPPORTED)
return false;
/* no stencil texturing prior to haswell */
if (devinfo->verx10 < 75) {
if (pformat == PIPE_FORMAT_S8_UINT ||
pformat == PIPE_FORMAT_X24S8_UINT ||
pformat == PIPE_FORMAT_S8X24_UINT ||
pformat == PIPE_FORMAT_X32_S8X24_UINT)
return false;
}
const struct isl_format_layout *fmtl = isl_format_get_layout(format);
const bool is_integer = isl_format_has_int_channel(format);
bool supported = true;
if (sample_count > 1)
supported &= isl_format_supports_multisampling(devinfo, format);
if (usage & PIPE_BIND_DEPTH_STENCIL) {
bool depth_fmts = format == ISL_FORMAT_R32_FLOAT_X8X24_TYPELESS ||
format == ISL_FORMAT_R32_FLOAT ||
format == ISL_FORMAT_R24_UNORM_X8_TYPELESS ||
format == ISL_FORMAT_R8_UINT;
/* Z16 is disabled here as on pre-GEN8 it's slower. */
if (devinfo->ver == 8)
depth_fmts |= format == ISL_FORMAT_R16_UNORM;
supported &= depth_fmts;
}
if (usage & PIPE_BIND_RENDER_TARGET) {
/* Alpha and luminance-alpha formats other than A8_UNORM are not
* renderable.
*
* For BLORP, we can apply the swizzle in the shader. But for
* general rendering, this would mean recompiling the shader, which
* we'd like to avoid doing. So we mark these formats non-renderable.
*
* We do support A8_UNORM as it's required and is renderable.
*/
if (pformat != PIPE_FORMAT_A8_UNORM &&
(util_format_is_alpha(pformat) ||
util_format_is_luminance_alpha(pformat)))
supported = false;
enum isl_format rt_format = format;
if (isl_format_is_rgbx(format) &&
!isl_format_supports_rendering(devinfo, format))
rt_format = isl_format_rgbx_to_rgba(format);
supported &= isl_format_supports_rendering(devinfo, rt_format);
if (!is_integer)
supported &= isl_format_supports_alpha_blending(devinfo, rt_format);
}
if (usage & PIPE_BIND_SHADER_IMAGE) {
/* Dataport doesn't support compression, and we can't resolve an MCS
* compressed surface. (Buffer images may have sample count of 0.)
*/
supported &= sample_count == 0;
supported &= isl_format_supports_typed_writes(devinfo, format);
supported &= isl_has_matching_typed_storage_image_format(devinfo, format);
}
if (usage & PIPE_BIND_SAMPLER_VIEW) {
supported &= isl_format_supports_sampling(devinfo, format);
/* disable Z16 unorm depth textures pre gen8 */
if (devinfo->ver < 8 && pformat == PIPE_FORMAT_Z16_UNORM)
supported = false;
bool ignore_filtering = false;
if (is_integer)
ignore_filtering = true;
/* I said them, but I lied them. */
if (devinfo->ver < 5 && (format == ISL_FORMAT_R32G32B32A32_FLOAT ||
format == ISL_FORMAT_R24_UNORM_X8_TYPELESS ||
format == ISL_FORMAT_R32_FLOAT ||
format == ISL_FORMAT_R32_FLOAT_X8X24_TYPELESS))
ignore_filtering = true;
if (!ignore_filtering)
supported &= isl_format_supports_filtering(devinfo, format);
/* Don't advertise 3-component RGB formats for non-buffer textures.
* This ensures that they are renderable from an API perspective since
* the state tracker will fall back to RGBA or RGBX, which are
* renderable. We want to render internally for copies and blits,
* even if the application doesn't.
*
* Buffer textures don't need to be renderable, so we support real RGB.
* This is useful for PBO upload, and 32-bit RGB support is mandatory.
*/
if (target != PIPE_BUFFER)
supported &= fmtl->bpb != 24 && fmtl->bpb != 48 && fmtl->bpb != 96;
}
if (usage & PIPE_BIND_VERTEX_BUFFER) {
supported &= isl_format_supports_vertex_fetch(devinfo, format);
if (devinfo->verx10 < 75) {
/* W/A: Pre-Haswell, the hardware doesn't really support the formats
* we'd like to use here, so upload everything as UINT and fix it in
* the shader
*/
if (format == ISL_FORMAT_R10G10B10A2_UNORM ||
format == ISL_FORMAT_B10G10R10A2_UNORM ||
format == ISL_FORMAT_R10G10B10A2_SNORM ||
format == ISL_FORMAT_B10G10R10A2_SNORM ||
format == ISL_FORMAT_R10G10B10A2_USCALED ||
format == ISL_FORMAT_B10G10R10A2_USCALED ||
format == ISL_FORMAT_R10G10B10A2_SSCALED ||
format == ISL_FORMAT_B10G10R10A2_SSCALED)
supported = true;
if (format == ISL_FORMAT_R8G8B8_SINT ||
format == ISL_FORMAT_R8G8B8_UINT ||
format == ISL_FORMAT_R16G16B16_SINT ||
format == ISL_FORMAT_R16G16B16_UINT)
supported = true;
}
}
if (usage & PIPE_BIND_INDEX_BUFFER) {
supported &= format == ISL_FORMAT_R8_UINT ||
format == ISL_FORMAT_R16_UINT ||
format == ISL_FORMAT_R32_UINT;
}
return supported;
}
@@ -0,0 +1,170 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* Macro and function definitions needed in order to use genxml.
*
* This should only be included in sources compiled per-generation.
*/
#include "crocus_batch.h"
#include "genxml/gen_macros.h"
#define __gen_address_type struct crocus_address
#define __gen_user_data struct crocus_batch
#define __gen_combine_address crocus_combine_address
static inline void *
__gen_get_batch_dwords(struct crocus_batch *batch, unsigned dwords)
{
return crocus_get_command_space(batch, dwords * sizeof(uint32_t));
}
static inline struct crocus_address
__gen_address_offset(struct crocus_address addr, uint64_t offset)
{
addr.offset += offset;
return addr;
}
static uint64_t
__gen_combine_address(struct crocus_batch *batch, void *location,
struct crocus_address addr, uint32_t delta)
{
uint32_t offset = (char *)location - (char *)batch->command.map;
if (addr.bo == NULL) {
return addr.offset + delta;
} else {
if (GFX_VER < 6 && crocus_ptr_in_state_buffer(batch, location)) {
offset = (char *) location - (char *) batch->state.map;
return crocus_state_reloc(batch, offset, addr.bo,
addr.offset + delta,
addr.reloc_flags);
}
assert(!crocus_ptr_in_state_buffer(batch, location));
offset = (char *) location - (char *) batch->command.map;
return crocus_command_reloc(batch, offset, addr.bo,
addr.offset + delta,
addr.reloc_flags);
}
}
static inline struct crocus_address
__gen_get_batch_address(struct crocus_batch *batch, void *location)
{
UNREACHABLE("Not supported by crocus");
}
#define __gen_address_type struct crocus_address
#define __gen_user_data struct crocus_batch
#define __genxml_cmd_length(cmd) cmd ## _length
#define __genxml_cmd_length_bias(cmd) cmd ## _length_bias
#define __genxml_cmd_header(cmd) cmd ## _header
#define __genxml_cmd_pack(cmd) cmd ## _pack
#define __genxml_reg_num(cmd) cmd ## _num
#include "genxml/genX_pack.h"
#include "genxml/gen_macros.h"
#include "genxml/genX_bits.h"
/* CS_GPR(15) is reserved for combining conditional rendering predicates
* with GL_ARB_indirect_parameters draw number predicates.
*/
#define MI_BUILDER_NUM_ALLOC_GPRS 15
#include "common/mi_builder.h"
#define _crocus_pack_command(batch, cmd, dst, name) \
for (struct cmd name = { __genxml_cmd_header(cmd) }, \
*_dst = (void *)(dst); __builtin_expect(_dst != NULL, 1); \
({ __genxml_cmd_pack(cmd)(batch, (void *)_dst, &name); \
_dst = NULL; \
}))
#define crocus_pack_command(cmd, dst, name) \
_crocus_pack_command(NULL, cmd, dst, name)
#define _crocus_pack_state(batch, cmd, dst, name) \
for (struct cmd name = {}, \
*_dst = (void *)(dst); __builtin_expect(_dst != NULL, 1); \
__genxml_cmd_pack(cmd)(batch, (void *)_dst, &name), \
_dst = NULL)
#define crocus_pack_state(cmd, dst, name) \
_crocus_pack_state(NULL, cmd, dst, name)
#define crocus_emit_cmd(batch, cmd, name) \
_crocus_pack_command(batch, cmd, __gen_get_batch_dwords(batch, __genxml_cmd_length(cmd)), name)
#define crocus_emit_merge(batch, dwords0, dwords1, num_dwords) \
do { \
uint32_t *dw = __gen_get_batch_dwords(batch, num_dwords); \
for (uint32_t i = 0; i < num_dwords; i++) \
dw[i] = (dwords0)[i] | (dwords1)[i]; \
VG(VALGRIND_CHECK_MEM_IS_DEFINED(dw, num_dwords)); \
} while (0)
#define crocus_emit_reg(batch, reg, name) \
for (struct reg name = {}, *_cont = (struct reg *)1; _cont != NULL; \
({ \
uint32_t _dw[__genxml_cmd_length(reg)]; \
__genxml_cmd_pack(reg)(NULL, _dw, &name); \
for (unsigned i = 0; i < __genxml_cmd_length(reg); i++) { \
crocus_emit_cmd(batch, GENX(MI_LOAD_REGISTER_IMM), lri) { \
lri.RegisterOffset = __genxml_reg_num(reg); \
lri.DataDWord = _dw[i]; \
} \
} \
_cont = NULL; \
}))
/**
* crocus_address constructor helpers:
*
* When using these to construct a CSO, pass NULL for \p bo, and manually
* pin the BO later. Otherwise, genxml's address handling will add the
* BO to the current batch's validation list at CSO creation time, rather
* than at draw time as desired.
*/
UNUSED static struct crocus_address
ro_bo(struct crocus_bo *bo, uint64_t offset)
{
return (struct crocus_address) { .bo = bo, .offset = offset, .reloc_flags = RELOC_32BIT };
}
UNUSED static struct crocus_address
rw_bo(struct crocus_bo *bo, uint64_t offset)
{
return (struct crocus_address) { .bo = bo, .offset = offset, .reloc_flags = RELOC_32BIT | RELOC_WRITE };
}
UNUSED static struct crocus_address
ggtt_bo(struct crocus_bo *bo, uint64_t offset)
{
return (struct crocus_address) { .bo = bo, .offset = offset, .reloc_flags = RELOC_WRITE | RELOC_NEEDS_GGTT };
}
@@ -0,0 +1,51 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/* GenX-specific function declarations.
*
* Don't include this directly, it will be included by crocus_context.h.
*
* NOTE: This header can be included multiple times, from the same file.
*/
/* crocus_state.c */
void genX(crocus_init_state)(struct crocus_context *ice);
void genX(crocus_init_screen_state)(struct crocus_screen *screen);
void genX(crocus_upload_urb)(struct crocus_batch *batch,
unsigned vs_size,
bool gs_present,
unsigned gs_size);
void genX(crocus_update_pma_fix)(struct crocus_context *ice,
struct crocus_batch *batch,
bool enable);
void
genX(crocus_framebuffer_init)(struct pipe_context *pctx, const struct pipe_framebuffer_state *fb, struct pipe_surface **cbufs, struct pipe_surface **zsbuf);
/* crocus_blorp.c */
void genX(crocus_init_blorp)(struct crocus_context *ice);
/* crocus_query.c */
void genX(crocus_init_query)(struct crocus_context *ice);
void genX(crocus_init_screen_query)(struct crocus_screen *screen);
/* crocus_blt.c */
void genX(crocus_init_blt)(struct crocus_screen *screen);
+337
View File
@@ -0,0 +1,337 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "crocus_monitor.h"
#include <xf86drm.h>
#include "crocus_screen.h"
#include "crocus_context.h"
#include "crocus_perf.h"
#include "perf/intel_perf.h"
#include "perf/intel_perf_query.h"
#include "perf/intel_perf_regs.h"
struct crocus_monitor_object {
int num_active_counters;
int *active_counters;
size_t result_size;
unsigned char *result_buffer;
struct intel_perf_query_object *query;
};
int
crocus_get_monitor_info(struct pipe_screen *pscreen, unsigned index,
struct pipe_driver_query_info *info)
{
const struct crocus_screen *screen = (struct crocus_screen *)pscreen;
struct intel_perf_config *perf_cfg = screen->perf_cfg;
assert(perf_cfg);
if (!perf_cfg)
return 0;
if (!info) {
/* return the number of metrics */
return perf_cfg->n_counters;
}
struct intel_perf_query_counter_info *counter_info = &perf_cfg->counter_infos[index];
struct intel_perf_query_info *query_info =
&perf_cfg->queries[intel_perf_query_counter_info_first_query(counter_info)];
struct intel_perf_query_counter *counter = counter_info->counter;
struct intel_perf_query_result results;
intel_perf_query_result_clear(&results);
info->group_id = counter_info->location.group_idx;
info->name = counter->name;
info->query_type = PIPE_QUERY_DRIVER_SPECIFIC + index;
if (counter->type == INTEL_PERF_COUNTER_TYPE_THROUGHPUT)
info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE;
else
info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE;
switch (counter->data_type) {
case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
case INTEL_PERF_COUNTER_DATA_TYPE_UINT32:
info->type = PIPE_DRIVER_QUERY_TYPE_UINT;
uint64_t val =
counter->oa_counter_max_uint64 ?
counter->oa_counter_max_uint64(perf_cfg, query_info, &results) : 0;
info->max_value.u32 = (uint32_t)val;
break;
case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
info->type = PIPE_DRIVER_QUERY_TYPE_UINT64;
info->max_value.u64 =
counter->oa_counter_max_uint64 ?
counter->oa_counter_max_uint64(perf_cfg, query_info, &results) : 0;
break;
case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE:
info->type = PIPE_DRIVER_QUERY_TYPE_FLOAT;
info->max_value.f =
counter->oa_counter_max_float ?
counter->oa_counter_max_float(perf_cfg, query_info, &results) : 0.0f;
break;
default:
assert(false);
break;
}
/* indicates that this is an OA query, not a pipeline statistics query */
info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
return 1;
}
static bool
crocus_monitor_init_metrics(struct crocus_screen *screen)
{
struct intel_perf_config *perf_cfg = intel_perf_new(screen);
if (unlikely(!perf_cfg))
return false;
screen->perf_cfg = perf_cfg;
crocus_perf_init_vtbl(perf_cfg);
intel_perf_init_metrics(perf_cfg, &screen->devinfo, screen->fd, true, true);
return perf_cfg->n_counters > 0;
}
int
crocus_get_monitor_group_info(struct pipe_screen *pscreen,
unsigned group_index,
struct pipe_driver_query_group_info *info)
{
struct crocus_screen *screen = (struct crocus_screen *)pscreen;
if (!screen->perf_cfg) {
if (!crocus_monitor_init_metrics(screen))
return 0;
}
const struct intel_perf_config *perf_cfg = screen->perf_cfg;
if (!info) {
/* return the count that can be queried */
return perf_cfg->n_queries;
}
if (group_index >= perf_cfg->n_queries) {
/* out of range */
return 0;
}
struct intel_perf_query_info *query = &perf_cfg->queries[group_index];
info->name = query->name;
info->max_active_queries = query->n_counters;
info->num_queries = query->n_counters;
return 1;
}
static void
crocus_init_monitor_ctx(struct crocus_context *ice)
{
struct crocus_screen *screen = (struct crocus_screen *) ice->ctx.screen;
ice->perf_ctx = intel_perf_new_context(ice);
if (unlikely(!ice->perf_ctx))
return;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
struct intel_perf_config *perf_cfg = screen->perf_cfg;
intel_perf_init_context(perf_ctx,
perf_cfg,
ice,
ice,
screen->bufmgr,
&screen->devinfo,
ice->batches[CROCUS_BATCH_RENDER].hw_ctx_id,
screen->fd);
}
/* entry point for GenPerfMonitorsAMD */
struct crocus_monitor_object *
crocus_create_monitor_object(struct crocus_context *ice,
unsigned num_queries,
unsigned *query_types)
{
struct crocus_screen *screen = (struct crocus_screen *) ice->ctx.screen;
struct intel_perf_config *perf_cfg = screen->perf_cfg;
struct intel_perf_query_object *query_obj = NULL;
/* initialize perf context if this has not already been done. This
* function is the first entry point that carries the gl context.
*/
if (ice->perf_ctx == NULL) {
crocus_init_monitor_ctx(ice);
}
struct intel_perf_context *perf_ctx = ice->perf_ctx;
assert(num_queries > 0);
int query_index = query_types[0] - PIPE_QUERY_DRIVER_SPECIFIC;
assert(query_index <= perf_cfg->n_counters);
const int group = perf_cfg->counter_infos[query_index].location.group_idx;
struct crocus_monitor_object *monitor =
calloc(1, sizeof(struct crocus_monitor_object));
if (unlikely(!monitor))
goto allocation_failure;
monitor->num_active_counters = num_queries;
monitor->active_counters = calloc(num_queries, sizeof(int));
if (unlikely(!monitor->active_counters))
goto allocation_failure;
for (int i = 0; i < num_queries; ++i) {
unsigned current_query = query_types[i];
unsigned current_query_index = current_query - PIPE_QUERY_DRIVER_SPECIFIC;
/* all queries must be in the same group */
assert(current_query_index <= perf_cfg->n_counters);
assert(perf_cfg->counter_infos[current_query_index].location.group_idx == group);
monitor->active_counters[i] =
perf_cfg->counter_infos[current_query_index].location.counter_idx;
}
/* create the intel_perf_query */
query_obj = intel_perf_new_query(perf_ctx, group);
if (unlikely(!query_obj))
goto allocation_failure;
monitor->query = query_obj;
monitor->result_size = perf_cfg->queries[group].data_size;
monitor->result_buffer = calloc(1, monitor->result_size);
if (unlikely(!monitor->result_buffer))
goto allocation_failure;
return monitor;
allocation_failure:
if (monitor) {
free(monitor->active_counters);
free(monitor->result_buffer);
}
free(query_obj);
free(monitor);
return NULL;
}
void
crocus_destroy_monitor_object(struct pipe_context *ctx,
struct crocus_monitor_object *monitor)
{
struct crocus_context *ice = (struct crocus_context *)ctx;
intel_perf_delete_query(ice->perf_ctx, monitor->query);
free(monitor->result_buffer);
monitor->result_buffer = NULL;
free(monitor->active_counters);
monitor->active_counters = NULL;
free(monitor);
}
bool
crocus_begin_monitor(struct pipe_context *ctx,
struct crocus_monitor_object *monitor)
{
struct crocus_context *ice = (void *) ctx;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
return intel_perf_begin_query(perf_ctx, monitor->query);
}
bool
crocus_end_monitor(struct pipe_context *ctx,
struct crocus_monitor_object *monitor)
{
struct crocus_context *ice = (void *) ctx;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
intel_perf_end_query(perf_ctx, monitor->query);
return true;
}
bool
crocus_get_monitor_result(struct pipe_context *ctx,
struct crocus_monitor_object *monitor,
bool wait,
union pipe_numeric_type_union *result)
{
struct crocus_context *ice = (void *) ctx;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
bool monitor_ready =
intel_perf_is_query_ready(perf_ctx, monitor->query, batch);
if (!monitor_ready) {
if (!wait)
return false;
intel_perf_wait_query(perf_ctx, monitor->query, batch);
}
assert(intel_perf_is_query_ready(perf_ctx, monitor->query, batch));
unsigned bytes_written;
intel_perf_get_query_data(perf_ctx, monitor->query, batch,
monitor->result_size,
(unsigned*) monitor->result_buffer,
&bytes_written);
if (bytes_written != monitor->result_size)
return false;
/* copy metrics into the batch result */
for (int i = 0; i < monitor->num_active_counters; ++i) {
int current_counter = monitor->active_counters[i];
const struct intel_perf_query_info *info =
intel_perf_query_info(monitor->query);
const struct intel_perf_query_counter *counter =
&info->counters[current_counter];
assert(intel_perf_query_counter_get_size(counter));
switch (counter->data_type) {
case INTEL_PERF_COUNTER_DATA_TYPE_UINT64:
result[i].u64 = *(uint64_t*)(monitor->result_buffer + counter->offset);
break;
case INTEL_PERF_COUNTER_DATA_TYPE_FLOAT:
result[i].f = *(float*)(monitor->result_buffer + counter->offset);
break;
case INTEL_PERF_COUNTER_DATA_TYPE_UINT32:
case INTEL_PERF_COUNTER_DATA_TYPE_BOOL32:
result[i].u64 = *(uint32_t*)(monitor->result_buffer + counter->offset);
break;
case INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE: {
double v = *(double*)(monitor->result_buffer + counter->offset);
result[i].f = v;
break;
}
default:
UNREACHABLE("unexpected counter data type");
}
}
return true;
}
@@ -0,0 +1,59 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CROCUS_MONITOR_H
#define CROCUS_MONITOR_H
#include "pipe/p_screen.h"
int crocus_get_monitor_info(struct pipe_screen *pscreen, unsigned index,
struct pipe_driver_query_info *info);
int crocus_get_monitor_group_info(struct pipe_screen *pscreen,
unsigned index,
struct pipe_driver_query_group_info *info);
struct crocus_context;
struct crocus_screen;
struct crocus_monitor_object *
crocus_create_monitor_object(struct crocus_context *ice,
unsigned num_queries,
unsigned *query_types);
struct pipe_query;
void crocus_destroy_monitor_object(struct pipe_context *ctx,
struct crocus_monitor_object *monitor);
bool
crocus_begin_monitor(struct pipe_context *ctx,
struct crocus_monitor_object *monitor);
bool
crocus_end_monitor(struct pipe_context *ctx,
struct crocus_monitor_object *monitor);
bool
crocus_get_monitor_result(struct pipe_context *ctx,
struct crocus_monitor_object *monitor,
bool wait,
union pipe_numeric_type_union *result);
#endif
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "crocus_perf.h"
#include "crocus_context.h"
static void *
crocus_oa_bo_alloc(void *bufmgr, const char *name, uint64_t size)
{
return crocus_bo_alloc(bufmgr, name, size);
}
static void
crocus_perf_emit_stall_at_pixel_scoreboard(struct crocus_context *ice)
{
crocus_emit_end_of_pipe_sync(&ice->batches[CROCUS_BATCH_RENDER],
"OA metrics",
PIPE_CONTROL_STALL_AT_SCOREBOARD);
}
static void
crocus_perf_emit_mi_report_perf_count(void *c,
void *bo,
uint32_t offset_in_bytes,
uint32_t report_id)
{
struct crocus_context *ice = c;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
batch->screen->vtbl.emit_mi_report_perf_count(batch, bo, offset_in_bytes, report_id);
}
static void
crocus_perf_batchbuffer_flush(void *c, const char *file, int line)
{
struct crocus_context *ice = c;
_crocus_batch_flush(&ice->batches[CROCUS_BATCH_RENDER], __FILE__, __LINE__);
}
static void
crocus_perf_store_register_mem(void *ctx, void *bo,
uint32_t reg, uint32_t reg_size,
uint32_t offset)
{
struct crocus_context *ice = ctx;
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
if (reg_size == 8) {
batch->screen->vtbl.store_register_mem64(batch, reg, bo, offset, false);
} else {
assert(reg_size == 4);
batch->screen->vtbl.store_register_mem32(batch, reg, bo, offset, false);
}
}
typedef void (*bo_unreference_t)(void *);
typedef void *(*bo_map_t)(void *, void *, unsigned flags);
typedef void (*bo_unmap_t)(void *);
typedef void (*emit_mi_report_t)(void *, void *, uint32_t, uint32_t);
typedef void (*emit_mi_flush_t)(void *);
typedef void (*store_register_mem_t)(void *ctx, void *bo,
uint32_t reg, uint32_t reg_size,
uint32_t offset);
typedef bool (*batch_references_t)(void *batch, void *bo);
typedef void (*bo_wait_rendering_t)(void *bo);
typedef int (*bo_busy_t)(void *bo);
void
crocus_perf_init_vtbl(struct intel_perf_config *perf_cfg)
{
perf_cfg->vtbl.bo_alloc = crocus_oa_bo_alloc;
perf_cfg->vtbl.bo_unreference = (bo_unreference_t)crocus_bo_unreference;
perf_cfg->vtbl.bo_map = (bo_map_t)crocus_bo_map;
perf_cfg->vtbl.bo_unmap = (bo_unmap_t)crocus_bo_unmap;
perf_cfg->vtbl.emit_stall_at_pixel_scoreboard =
(emit_mi_flush_t)crocus_perf_emit_stall_at_pixel_scoreboard;
perf_cfg->vtbl.emit_mi_report_perf_count =
(emit_mi_report_t)crocus_perf_emit_mi_report_perf_count;
perf_cfg->vtbl.batchbuffer_flush = crocus_perf_batchbuffer_flush;
perf_cfg->vtbl.store_register_mem =
(store_register_mem_t) crocus_perf_store_register_mem;
perf_cfg->vtbl.batch_references = (batch_references_t)crocus_batch_references;
perf_cfg->vtbl.bo_wait_rendering =
(bo_wait_rendering_t)crocus_bo_wait_rendering;
perf_cfg->vtbl.bo_busy = (bo_busy_t)crocus_bo_busy;
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CROCUS_PERF_H
#define CROCUS_PERF_H
#include "perf/intel_perf.h"
#include "perf/intel_perf_query.h"
void crocus_perf_init_vtbl(struct intel_perf_config *cfg);
#endif /* CROCUS_PERF_H */
@@ -0,0 +1,263 @@
/*
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <xf86drm.h>
#include "crocus_context.h"
#include "crocus_perf.h"
#include "main/mtypes.h"
struct crocus_perf_query {
struct gl_perf_query_object base;
struct intel_perf_query_object *query;
bool begin_succeeded;
};
static unsigned
crocus_init_perf_query_info(struct pipe_context *pipe)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_screen *screen = (struct crocus_screen *) ice->ctx.screen;
struct intel_perf_config *perf_cfg = NULL;
/* make sure pipe perf counter type/data-type enums are matched with intel_perf's */
STATIC_ASSERT(PIPE_PERF_COUNTER_TYPE_EVENT == (enum pipe_perf_counter_type)INTEL_PERF_COUNTER_TYPE_EVENT);
STATIC_ASSERT(PIPE_PERF_COUNTER_TYPE_DURATION_NORM == (enum pipe_perf_counter_type)INTEL_PERF_COUNTER_TYPE_DURATION_NORM);
STATIC_ASSERT(PIPE_PERF_COUNTER_TYPE_DURATION_RAW == (enum pipe_perf_counter_type)INTEL_PERF_COUNTER_TYPE_DURATION_RAW);
STATIC_ASSERT(PIPE_PERF_COUNTER_TYPE_THROUGHPUT == (enum pipe_perf_counter_type)INTEL_PERF_COUNTER_TYPE_THROUGHPUT);
STATIC_ASSERT(PIPE_PERF_COUNTER_TYPE_RAW == (enum pipe_perf_counter_type)INTEL_PERF_COUNTER_TYPE_RAW);
STATIC_ASSERT(PIPE_PERF_COUNTER_DATA_TYPE_BOOL32 == (enum pipe_perf_counter_data_type)INTEL_PERF_COUNTER_DATA_TYPE_BOOL32);
STATIC_ASSERT(PIPE_PERF_COUNTER_DATA_TYPE_UINT32 == (enum pipe_perf_counter_data_type)INTEL_PERF_COUNTER_DATA_TYPE_UINT32);
STATIC_ASSERT(PIPE_PERF_COUNTER_DATA_TYPE_UINT64 == (enum pipe_perf_counter_data_type)INTEL_PERF_COUNTER_DATA_TYPE_UINT64);
STATIC_ASSERT(PIPE_PERF_COUNTER_DATA_TYPE_FLOAT == (enum pipe_perf_counter_data_type)INTEL_PERF_COUNTER_DATA_TYPE_FLOAT);
STATIC_ASSERT(PIPE_PERF_COUNTER_DATA_TYPE_DOUBLE == (enum pipe_perf_counter_data_type)INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE);
if (!ice->perf_ctx)
ice->perf_ctx = intel_perf_new_context(ice);
if (unlikely(!ice->perf_ctx))
return 0;
perf_cfg = intel_perf_config(ice->perf_ctx);
if (perf_cfg)
return perf_cfg->n_queries;
perf_cfg = intel_perf_new(ice->perf_ctx);
crocus_perf_init_vtbl(perf_cfg);
intel_perf_init_metrics(perf_cfg, &screen->devinfo, screen->fd,
true /* pipeline_statistics */,
true /* register snapshots */);
intel_perf_init_context(ice->perf_ctx,
perf_cfg,
ice,
ice,
screen->bufmgr,
&screen->devinfo,
ice->batches[CROCUS_BATCH_RENDER].hw_ctx_id,
screen->fd);
return perf_cfg->n_queries;
}
static struct pipe_query *
crocus_new_perf_query_obj(struct pipe_context *pipe, unsigned query_index)
{
struct crocus_context *ice = (void *) pipe;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
struct intel_perf_query_object * obj =
intel_perf_new_query(perf_ctx, query_index);
if (unlikely(!obj))
return NULL;
struct crocus_perf_query *q = calloc(1, sizeof(struct crocus_perf_query));
if (unlikely(!q)) {
intel_perf_delete_query(perf_ctx, obj);
return NULL;
}
q->query = obj;
return (struct pipe_query *)&q->base;
}
static bool
crocus_begin_perf_query(struct pipe_context *pipe, struct pipe_query *q)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_perf_query *perf_query= (struct crocus_perf_query *) q;
struct intel_perf_query_object *obj = perf_query->query;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
return (perf_query->begin_succeeded = intel_perf_begin_query(perf_ctx, obj));
}
static void
crocus_end_perf_query(struct pipe_context *pipe, struct pipe_query *q)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_perf_query *perf_query = (struct crocus_perf_query *) q;
struct intel_perf_query_object *obj = perf_query->query;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
if (perf_query->begin_succeeded)
intel_perf_end_query(perf_ctx, obj);
}
static void
crocus_delete_perf_query(struct pipe_context *pipe, struct pipe_query *q)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_perf_query *perf_query = (struct crocus_perf_query *) q;
struct intel_perf_query_object *obj = perf_query->query;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
intel_perf_delete_query(perf_ctx, obj);
free(q);
}
static void
crocus_get_perf_query_info(struct pipe_context *pipe,
unsigned query_index,
const char **name,
uint32_t *data_size,
uint32_t *n_counters,
uint32_t *n_active)
{
struct crocus_context *ice = (void *) pipe;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
struct intel_perf_config *perf_cfg = intel_perf_config(perf_ctx);
const struct intel_perf_query_info *info = &perf_cfg->queries[query_index];
*name = info->name;
*data_size = info->data_size;
*n_counters = info->n_counters;
*n_active = intel_perf_active_queries(perf_ctx, info);
}
static void
crocus_get_perf_counter_info(struct pipe_context *pipe,
unsigned query_index,
unsigned counter_index,
const char **name,
const char **desc,
uint32_t *offset,
uint32_t *data_size,
uint32_t *type_enum,
uint32_t *data_type_enum,
uint64_t *raw_max)
{
struct crocus_context *ice = (void *) pipe;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
struct intel_perf_config *perf_cfg = intel_perf_config(perf_ctx);
const struct intel_perf_query_info *info = &perf_cfg->queries[query_index];
const struct intel_perf_query_counter *counter =
&info->counters[counter_index];
struct intel_perf_query_result results;
intel_perf_query_result_clear(&results);
*name = counter->name;
*desc = counter->desc;
*offset = counter->offset;
*data_size = intel_perf_query_counter_get_size(counter);
*type_enum = counter->type;
*data_type_enum = counter->data_type;
if (counter->oa_counter_max_uint64) {
if (counter->data_type == INTEL_PERF_COUNTER_DATA_TYPE_FLOAT ||
counter->data_type == INTEL_PERF_COUNTER_DATA_TYPE_DOUBLE)
*raw_max = counter->oa_counter_max_float(perf_cfg, info, &results);
else
*raw_max = counter->oa_counter_max_uint64(perf_cfg, info, &results);
} else {
*raw_max = 0;
}
}
static void
crocus_wait_perf_query(struct pipe_context *pipe, struct pipe_query *q)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_perf_query *perf_query = (struct crocus_perf_query *) q;
struct intel_perf_query_object *obj = perf_query->query;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
if (perf_query->begin_succeeded)
intel_perf_wait_query(perf_ctx, obj, &ice->batches[CROCUS_BATCH_RENDER]);
}
static bool
crocus_is_perf_query_ready(struct pipe_context *pipe, struct pipe_query *q)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_perf_query *perf_query = (struct crocus_perf_query *) q;
struct intel_perf_query_object *obj = perf_query->query;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
if (perf_query->base.Ready)
return true;
if (!perf_query->begin_succeeded)
return true;
return intel_perf_is_query_ready(perf_ctx, obj,
&ice->batches[CROCUS_BATCH_RENDER]);
}
static bool
crocus_get_perf_query_data(struct pipe_context *pipe,
struct pipe_query *q,
size_t data_size,
uint32_t *data,
uint32_t *bytes_written)
{
struct crocus_context *ice = (void *) pipe;
struct crocus_perf_query *perf_query = (struct crocus_perf_query *) q;
struct intel_perf_query_object *obj = perf_query->query;
struct intel_perf_context *perf_ctx = ice->perf_ctx;
if (perf_query->begin_succeeded) {
intel_perf_get_query_data(perf_ctx, obj, &ice->batches[CROCUS_BATCH_RENDER],
data_size, data, bytes_written);
}
return perf_query->begin_succeeded;
}
void
crocus_init_perfquery_functions(struct pipe_context *ctx)
{
ctx->init_intel_perf_query_info = crocus_init_perf_query_info;
ctx->get_intel_perf_query_info = crocus_get_perf_query_info;
ctx->get_intel_perf_query_counter_info = crocus_get_perf_counter_info;
ctx->new_intel_perf_query_obj = crocus_new_perf_query_obj;
ctx->begin_intel_perf_query = crocus_begin_perf_query;
ctx->end_intel_perf_query = crocus_end_perf_query;
ctx->delete_intel_perf_query = crocus_delete_perf_query;
ctx->wait_intel_perf_query = crocus_wait_perf_query;
ctx->is_intel_perf_query_ready = crocus_is_perf_query_ready;
ctx->get_intel_perf_query_data = crocus_get_perf_query_data;
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CROCUS_PIPE_H
#define CROCUS_PIPE_H
#include "pipe/p_defines.h"
#include "compiler/shader_enums.h"
static inline mesa_shader_stage
stage_from_pipe(mesa_shader_stage pstage)
{
return (mesa_shader_stage)pstage;
}
static inline mesa_shader_stage
stage_to_pipe(mesa_shader_stage stage)
{
return (mesa_shader_stage)stage;
}
/**
* Convert an swizzle enumeration (i.e. PIPE_SWIZZLE_X) to one of the HW's
* "Shader Channel Select" enumerations (i.e. SCS_RED). The mappings are
*
* SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_ZERO, SWIZZLE_ONE
* 0 1 2 3 4 5
* 4 5 6 7 0 1
* SCS_RED, SCS_GREEN, SCS_BLUE, SCS_ALPHA, SCS_ZERO, SCS_ONE
*
* which is simply adding 4 then modding by 8 (or anding with 7).
*/
static inline enum isl_channel_select
pipe_swizzle_to_isl_channel(enum pipe_swizzle swizzle)
{
return (swizzle + 4) & 7;
}
#endif
@@ -0,0 +1,376 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_pipe_control.c
*
* PIPE_CONTROL is the main flushing and synchronization primitive on Intel
* GPUs. It can invalidate caches, stall until rendering reaches various
* stages of completion, write to memory, and other things. In a way, it's
* a swiss army knife command - it has all kinds of capabilities, but some
* significant limitations as well.
*
* Unfortunately, it's notoriously complicated and difficult to use. Many
* sub-commands can't be used together. Some are meant to be used at the
* top of the pipeline (invalidating caches before drawing), while some are
* meant to be used at the end (stalling or flushing after drawing).
*
* Also, there's a list of restrictions a mile long, which vary by generation.
* Do this before doing that, or suffer the consequences (usually a GPU hang).
*
* This file contains helpers for emitting them safely. You can simply call
* crocus_emit_pipe_control_flush() with the desired operations (as logical
* PIPE_CONTROL_* bits), and it will take care of splitting it into multiple
* PIPE_CONTROL commands as necessary. The per-generation workarounds are
* applied in crocus_emit_raw_pipe_control() in crocus_state.c.
*/
#include "crocus_context.h"
#include "util/hash_table.h"
#include "util/set.h"
/**
* Emit a PIPE_CONTROL with various flushing flags.
*
* The caller is responsible for deciding what flags are appropriate for the
* given generation.
*/
void
crocus_emit_pipe_control_flush(struct crocus_batch *batch,
const char *reason,
uint32_t flags)
{
const struct intel_device_info *devinfo = &batch->screen->devinfo;
if (devinfo->ver >= 6 &&
(flags & PIPE_CONTROL_CACHE_FLUSH_BITS) &&
(flags & PIPE_CONTROL_CACHE_INVALIDATE_BITS)) {
/* A pipe control command with flush and invalidate bits set
* simultaneously is an inherently racy operation on Gen6+ if the
* contents of the flushed caches were intended to become visible from
* any of the invalidated caches. Split it in two PIPE_CONTROLs, the
* first one should stall the pipeline to make sure that the flushed R/W
* caches are coherent with memory once the specified R/O caches are
* invalidated. On pre-Gen6 hardware the (implicit) R/O cache
* invalidation seems to happen at the bottom of the pipeline together
* with any write cache flush, so this shouldn't be a concern. In order
* to ensure a full stall, we do an end-of-pipe sync.
*/
crocus_emit_end_of_pipe_sync(batch, reason,
flags & PIPE_CONTROL_CACHE_FLUSH_BITS);
flags &= ~(PIPE_CONTROL_CACHE_FLUSH_BITS | PIPE_CONTROL_CS_STALL);
}
batch->screen->vtbl.emit_raw_pipe_control(batch, reason, flags, NULL, 0, 0);
}
/**
* Emit a PIPE_CONTROL that writes to a buffer object.
*
* \p flags should contain one of the following items:
* - PIPE_CONTROL_WRITE_IMMEDIATE
* - PIPE_CONTROL_WRITE_TIMESTAMP
* - PIPE_CONTROL_WRITE_DEPTH_COUNT
*/
void
crocus_emit_pipe_control_write(struct crocus_batch *batch,
const char *reason, uint32_t flags,
struct crocus_bo *bo, uint32_t offset,
uint64_t imm)
{
batch->screen->vtbl.emit_raw_pipe_control(batch, reason, flags, bo, offset, imm);
}
/**
* Restriction [DevSNB, DevIVB]:
*
* Prior to changing Depth/Stencil Buffer state (i.e. any combination of
* 3DSTATE_DEPTH_BUFFER, 3DSTATE_CLEAR_PARAMS, 3DSTATE_STENCIL_BUFFER,
* 3DSTATE_HIER_DEPTH_BUFFER) SW must first issue a pipelined depth stall
* (PIPE_CONTROL with Depth Stall bit set), followed by a pipelined depth
* cache flush (PIPE_CONTROL with Depth Flush Bit set), followed by
* another pipelined depth stall (PIPE_CONTROL with Depth Stall bit set),
* unless SW can otherwise guarantee that the pipeline from WM onwards is
* already flushed (e.g., via a preceding MI_FLUSH).
*/
void
crocus_emit_depth_stall_flushes(struct crocus_batch *batch)
{
UNUSED const struct intel_device_info *devinfo = &batch->screen->devinfo;
assert(devinfo->ver >= 6);
/* Starting on BDW, these pipe controls are unnecessary.
*
* WM HW will internally manage the draining pipe and flushing of the caches
* when this command is issued. The PIPE_CONTROL restrictions are removed.
*/
if (devinfo->ver >= 8)
return;
crocus_emit_pipe_control_flush(batch, "depth stall", PIPE_CONTROL_DEPTH_STALL);
crocus_emit_pipe_control_flush(batch, "depth stall", PIPE_CONTROL_DEPTH_CACHE_FLUSH);
crocus_emit_pipe_control_flush(batch, "depth stall", PIPE_CONTROL_DEPTH_STALL);
}
/*
* From Sandybridge PRM, volume 2, "1.7.2 End-of-Pipe Synchronization":
*
* Write synchronization is a special case of end-of-pipe
* synchronization that requires that the render cache and/or depth
* related caches are flushed to memory, where the data will become
* globally visible. This type of synchronization is required prior to
* SW (CPU) actually reading the result data from memory, or initiating
* an operation that will use as a read surface (such as a texture
* surface) a previous render target and/or depth/stencil buffer
*
* From Haswell PRM, volume 2, part 1, "End-of-Pipe Synchronization":
*
* Exercising the write cache flush bits (Render Target Cache Flush
* Enable, Depth Cache Flush Enable, DC Flush) in PIPE_CONTROL only
* ensures the write caches are flushed and doesn't guarantee the data
* is globally visible.
*
* SW can track the completion of the end-of-pipe-synchronization by
* using "Notify Enable" and "PostSync Operation - Write Immediate
* Data" in the PIPE_CONTROL command.
*/
void
crocus_emit_end_of_pipe_sync(struct crocus_batch *batch,
const char *reason, uint32_t flags)
{
const struct intel_device_info *devinfo = &batch->screen->devinfo;
if (devinfo->ver >= 6) {
/* From Sandybridge PRM, volume 2, "1.7.3.1 Writing a Value to Memory":
*
* "The most common action to perform upon reaching a synchronization
* point is to write a value out to memory. An immediate value
* (included with the synchronization command) may be written."
*
* From Broadwell PRM, volume 7, "End-of-Pipe Synchronization":
*
* "In case the data flushed out by the render engine is to be read
* back in to the render engine in coherent manner, then the render
* engine has to wait for the fence completion before accessing the
* flushed data. This can be achieved by following means on various
* products: PIPE_CONTROL command with CS Stall and the required
* write caches flushed with Post-Sync-Operation as Write Immediate
* Data.
*
* Example:
* - Workload-1 (3D/GPGPU/MEDIA)
* - PIPE_CONTROL (CS Stall, Post-Sync-Operation Write Immediate
* Data, Required Write Cache Flush bits set)
* - Workload-2 (Can use the data produce or output by Workload-1)
*/
crocus_emit_pipe_control_write(batch, reason,
flags | PIPE_CONTROL_CS_STALL |
PIPE_CONTROL_WRITE_IMMEDIATE,
batch->ice->workaround_bo,
batch->ice->workaround_offset, 0);
if (batch->screen->devinfo.platform == INTEL_PLATFORM_HSW) {
#define GEN7_3DPRIM_START_INSTANCE 0x243C
batch->screen->vtbl.load_register_mem32(batch, GEN7_3DPRIM_START_INSTANCE,
batch->ice->workaround_bo,
batch->ice->workaround_offset);
}
} else {
/* On gen4-5, a regular pipe control seems to suffice. */
crocus_emit_pipe_control_flush(batch, reason, flags);
}
}
/* Emit a pipelined flush to either flush render and texture cache for
* reading from a FBO-drawn texture, or flush so that frontbuffer
* render appears on the screen in DRI1.
*
* This is also used for the always_flush_cache driconf debug option.
*/
void
crocus_emit_mi_flush(struct crocus_batch *batch)
{
const struct intel_device_info *devinfo = &batch->screen->devinfo;
int flags = PIPE_CONTROL_RENDER_TARGET_FLUSH;
if (devinfo->ver >= 6) {
flags |= PIPE_CONTROL_INSTRUCTION_INVALIDATE |
PIPE_CONTROL_CONST_CACHE_INVALIDATE |
PIPE_CONTROL_DATA_CACHE_FLUSH |
PIPE_CONTROL_DEPTH_CACHE_FLUSH |
PIPE_CONTROL_VF_CACHE_INVALIDATE |
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
PIPE_CONTROL_CS_STALL;
}
crocus_emit_pipe_control_flush(batch, "mi flush", flags);
}
/**
* Emits a PIPE_CONTROL with a non-zero post-sync operation, for
* implementing two workarounds on gen6. From section 1.4.7.1
* "PIPE_CONTROL" of the Sandy Bridge PRM volume 2 part 1:
*
* [DevSNB-C+{W/A}] Before any depth stall flush (including those
* produced by non-pipelined state commands), software needs to first
* send a PIPE_CONTROL with no bits set except Post-Sync Operation !=
* 0.
*
* [Dev-SNB{W/A}]: Before a PIPE_CONTROL with Write Cache Flush Enable
* =1, a PIPE_CONTROL with any non-zero post-sync-op is required.
*
* And the workaround for these two requires this workaround first:
*
* [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
* BEFORE the pipe-control with a post-sync op and no write-cache
* flushes.
*
* And this last workaround is tricky because of the requirements on
* that bit. From section 1.4.7.2.3 "Stall" of the Sandy Bridge PRM
* volume 2 part 1:
*
* "1 of the following must also be set:
* - Render Target Cache Flush Enable ([12] of DW1)
* - Depth Cache Flush Enable ([0] of DW1)
* - Stall at Pixel Scoreboard ([1] of DW1)
* - Depth Stall ([13] of DW1)
* - Post-Sync Operation ([13] of DW1)
* - Notify Enable ([8] of DW1)"
*
* The cache flushes require the workaround flush that triggered this
* one, so we can't use it. Depth stall would trigger the same.
* Post-sync nonzero is what triggered this second workaround, so we
* can't use that one either. Notify enable is IRQs, which aren't
* really our business. That leaves only stall at scoreboard.
*/
void
crocus_emit_post_sync_nonzero_flush(struct crocus_batch *batch)
{
crocus_emit_pipe_control_flush(batch, "nonzero",
PIPE_CONTROL_CS_STALL |
PIPE_CONTROL_STALL_AT_SCOREBOARD);
crocus_emit_pipe_control_write(batch, "nonzero",
PIPE_CONTROL_WRITE_IMMEDIATE,
batch->ice->workaround_bo,
batch->ice->workaround_offset, 0);
}
/**
* Flush and invalidate all caches (for debugging purposes).
*/
void
crocus_flush_all_caches(struct crocus_batch *batch)
{
crocus_emit_pipe_control_flush(batch, "debug: flush all caches",
PIPE_CONTROL_CS_STALL |
PIPE_CONTROL_DATA_CACHE_FLUSH |
PIPE_CONTROL_DEPTH_CACHE_FLUSH |
PIPE_CONTROL_RENDER_TARGET_FLUSH |
PIPE_CONTROL_VF_CACHE_INVALIDATE |
PIPE_CONTROL_INSTRUCTION_INVALIDATE |
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
PIPE_CONTROL_CONST_CACHE_INVALIDATE |
PIPE_CONTROL_STATE_CACHE_INVALIDATE);
}
static void
crocus_texture_barrier(struct pipe_context *ctx, unsigned flags)
{
struct crocus_context *ice = (void *) ctx;
struct crocus_batch *render_batch = &ice->batches[CROCUS_BATCH_RENDER];
struct crocus_batch *compute_batch = &ice->batches[CROCUS_BATCH_COMPUTE];
const struct intel_device_info *devinfo = &render_batch->screen->devinfo;
if (devinfo->ver < 6) {
crocus_emit_mi_flush(render_batch);
return;
}
if (render_batch->contains_draw) {
crocus_batch_maybe_flush(render_batch, 48);
crocus_emit_pipe_control_flush(render_batch,
"API: texture barrier (1/2)",
(flags == 1 ? PIPE_CONTROL_DEPTH_CACHE_FLUSH : 0) |
PIPE_CONTROL_RENDER_TARGET_FLUSH |
PIPE_CONTROL_CS_STALL);
crocus_emit_pipe_control_flush(render_batch,
"API: texture barrier (2/2)",
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
}
if (compute_batch->contains_draw) {
crocus_batch_maybe_flush(compute_batch, 48);
crocus_emit_pipe_control_flush(compute_batch,
"API: texture barrier (1/2)",
PIPE_CONTROL_CS_STALL);
crocus_emit_pipe_control_flush(compute_batch,
"API: texture barrier (2/2)",
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
}
}
static void
crocus_memory_barrier(struct pipe_context *ctx, unsigned flags)
{
struct crocus_context *ice = (void *) ctx;
unsigned bits = PIPE_CONTROL_DATA_CACHE_FLUSH | PIPE_CONTROL_CS_STALL;
const struct intel_device_info *devinfo = &ice->batches[0].screen->devinfo;
assert(devinfo->ver >= 7);
if (flags & (PIPE_BARRIER_VERTEX_BUFFER |
PIPE_BARRIER_INDEX_BUFFER |
PIPE_BARRIER_INDIRECT_BUFFER)) {
bits |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
}
if (flags & PIPE_BARRIER_CONSTANT_BUFFER) {
bits |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
PIPE_CONTROL_CONST_CACHE_INVALIDATE;
}
if (flags & (PIPE_BARRIER_TEXTURE | PIPE_BARRIER_FRAMEBUFFER)) {
bits |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
PIPE_CONTROL_RENDER_TARGET_FLUSH;
}
/* Typed surface messages are handled by the render cache on IVB, so we
* need to flush it too.
*/
if (devinfo->verx10 < 75)
bits |= PIPE_CONTROL_RENDER_TARGET_FLUSH;
for (int i = 0; i < ice->batch_count; i++) {
if (ice->batches[i].contains_draw) {
crocus_batch_maybe_flush(&ice->batches[i], 24);
crocus_emit_pipe_control_flush(&ice->batches[i], "API: memory barrier",
bits);
}
}
}
void
crocus_init_flush_functions(struct pipe_context *ctx)
{
ctx->memory_barrier = crocus_memory_barrier;
ctx->texture_barrier = crocus_texture_barrier;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,346 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_program_cache.c
*
* The in-memory program cache. This is basically a hash table mapping
* API-specified shaders and a state key to a compiled variant. It also
* takes care of uploading shader assembly into a BO for use on the GPU.
*/
#include <stdio.h>
#include <errno.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/u_atomic.h"
#include "util/u_upload_mgr.h"
#include "compiler/nir/nir.h"
#include "compiler/nir/nir_builder.h"
#include "intel/compiler/elk/elk_compiler.h"
#include "intel/compiler/elk/elk_disasm.h"
#include "intel/compiler/elk/elk_nir.h"
#include "crocus_context.h"
#include "crocus_resource.h"
struct keybox {
uint16_t size;
enum crocus_program_cache_id cache_id;
uint8_t data[0];
};
static struct keybox *
make_keybox(void *mem_ctx, enum crocus_program_cache_id cache_id,
const void *key, uint32_t key_size)
{
struct keybox *keybox =
ralloc_size(mem_ctx, sizeof(struct keybox) + key_size);
keybox->cache_id = cache_id;
keybox->size = key_size;
memcpy(keybox->data, key, key_size);
return keybox;
}
static uint32_t
keybox_hash(const void *void_key)
{
const struct keybox *key = void_key;
return _mesa_hash_data(&key->cache_id, key->size + sizeof(key->cache_id));
}
static bool
keybox_equals(const void *void_a, const void *void_b)
{
const struct keybox *a = void_a, *b = void_b;
if (a->size != b->size)
return false;
return memcmp(a->data, b->data, a->size) == 0;
}
struct crocus_compiled_shader *
crocus_find_cached_shader(struct crocus_context *ice,
enum crocus_program_cache_id cache_id,
uint32_t key_size, const void *key)
{
struct keybox *keybox = make_keybox(NULL, cache_id, key, key_size);
struct hash_entry *entry =
_mesa_hash_table_search(ice->shaders.cache, keybox);
ralloc_free(keybox);
return entry ? entry->data : NULL;
}
const void *
crocus_find_previous_compile(const struct crocus_context *ice,
enum crocus_program_cache_id cache_id,
unsigned program_string_id)
{
hash_table_foreach(ice->shaders.cache, entry) {
const struct keybox *keybox = entry->key;
const struct elk_base_prog_key *key = (const void *)keybox->data;
if (keybox->cache_id == cache_id &&
key->program_string_id == program_string_id) {
return keybox->data;
}
}
return NULL;
}
/**
* Look for an existing entry in the cache that has identical assembly code.
*
* This is useful for programs generating shaders at runtime, where multiple
* distinct shaders (from an API perspective) may compile to the same assembly
* in our backend. This saves space in the program cache buffer.
*/
static const struct crocus_compiled_shader *
find_existing_assembly(struct hash_table *cache, void *map,
const void *assembly, unsigned assembly_size)
{
hash_table_foreach (cache, entry) {
const struct crocus_compiled_shader *existing = entry->data;
if (existing->map_size != assembly_size)
continue;
if (memcmp(map + existing->offset, assembly, assembly_size) == 0)
return existing;
}
return NULL;
}
static void
crocus_cache_new_bo(struct crocus_context *ice,
uint32_t new_size)
{
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
struct crocus_bo *new_bo;
new_bo = crocus_bo_alloc(screen->bufmgr, "program cache", new_size);
void *map = crocus_bo_map(NULL, new_bo, MAP_READ | MAP_WRITE |
MAP_ASYNC | MAP_PERSISTENT);
if (ice->shaders.cache_next_offset != 0) {
memcpy(map, ice->shaders.cache_bo_map, ice->shaders.cache_next_offset);
}
crocus_bo_unmap(ice->shaders.cache_bo);
crocus_bo_unreference(ice->shaders.cache_bo);
ice->shaders.cache_bo = new_bo;
ice->shaders.cache_bo_map = map;
if (screen->devinfo.ver <= 5) {
/* reemit all shaders on GEN4 only. */
ice->state.dirty |= CROCUS_DIRTY_CLIP | CROCUS_DIRTY_RASTER |
CROCUS_DIRTY_WM;
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_VS;
}
ice->batches[CROCUS_BATCH_RENDER].state_base_address_emitted = false;
ice->batches[CROCUS_BATCH_COMPUTE].state_base_address_emitted = false;
/* unset state base address */
}
static uint32_t
crocus_alloc_item_data(struct crocus_context *ice, uint32_t size)
{
if (ice->shaders.cache_next_offset + size > ice->shaders.cache_bo->size) {
uint32_t new_size = ice->shaders.cache_bo->size * 2;
while (ice->shaders.cache_next_offset + size > new_size)
new_size *= 2;
crocus_cache_new_bo(ice, new_size);
}
uint32_t offset = ice->shaders.cache_next_offset;
/* Programs are always 64-byte aligned, so set up the next one now */
ice->shaders.cache_next_offset = align(offset + size, 64);
return offset;
}
struct crocus_compiled_shader *
crocus_upload_shader(struct crocus_context *ice,
enum crocus_program_cache_id cache_id, uint32_t key_size,
const void *key, const void *assembly, uint32_t asm_size,
struct elk_stage_prog_data *prog_data,
uint32_t prog_data_size, uint32_t *streamout,
enum elk_param_builtin *system_values,
unsigned num_system_values, unsigned num_cbufs,
const struct crocus_binding_table *bt)
{
struct hash_table *cache = ice->shaders.cache;
struct crocus_compiled_shader *shader =
rzalloc_size(cache, sizeof(struct crocus_compiled_shader));
const struct crocus_compiled_shader *existing = find_existing_assembly(
cache, ice->shaders.cache_bo_map, assembly, asm_size);
/* If we can find a matching prog in the cache already, then reuse the
* existing stuff without creating new copy into the underlying buffer
* object. This is notably useful for programs generating shaders at
* runtime, where multiple shaders may compile to the same thing in our
* backend.
*/
if (existing) {
shader->offset = existing->offset;
shader->map_size = existing->map_size;
} else {
shader->offset = crocus_alloc_item_data(ice, asm_size);
shader->map_size = asm_size;
memcpy(ice->shaders.cache_bo_map + shader->offset, assembly, asm_size);
}
shader->prog_data = prog_data;
shader->prog_data_size = prog_data_size;
shader->streamout = streamout;
shader->system_values = system_values;
shader->num_system_values = num_system_values;
shader->num_cbufs = num_cbufs;
shader->bt = *bt;
ralloc_steal(shader, shader->prog_data);
if (prog_data_size > 16)
ralloc_steal(shader->prog_data, prog_data->param);
ralloc_steal(shader, shader->streamout);
ralloc_steal(shader, shader->system_values);
struct keybox *keybox = make_keybox(shader, cache_id, key, key_size);
_mesa_hash_table_insert(ice->shaders.cache, keybox, shader);
return shader;
}
bool
crocus_blorp_lookup_shader(struct blorp_batch *blorp_batch, const void *key,
uint32_t key_size, uint32_t *kernel_out,
void *prog_data_out)
{
struct blorp_context *blorp = blorp_batch->blorp;
struct crocus_context *ice = blorp->driver_ctx;
struct crocus_compiled_shader *shader =
crocus_find_cached_shader(ice, CROCUS_CACHE_BLORP, key_size, key);
if (!shader)
return false;
*kernel_out = shader->offset;
*((void **)prog_data_out) = shader->prog_data;
return true;
}
bool
crocus_blorp_upload_shader(struct blorp_batch *blorp_batch, uint32_t stage,
const void *key, uint32_t key_size,
const void *kernel, uint32_t kernel_size,
const void *prog_data_templ,
uint32_t prog_data_size, uint32_t *kernel_out,
void *prog_data_out)
{
struct blorp_context *blorp = blorp_batch->blorp;
struct crocus_context *ice = blorp->driver_ctx;
struct elk_stage_prog_data *prog_data = ralloc_size(NULL, prog_data_size);
memcpy(prog_data, prog_data_templ, prog_data_size);
struct crocus_binding_table bt;
memset(&bt, 0, sizeof(bt));
struct crocus_compiled_shader *shader = crocus_upload_shader(
ice, CROCUS_CACHE_BLORP, key_size, key, kernel, kernel_size, prog_data,
prog_data_size, NULL, NULL, 0, 0, &bt);
*kernel_out = shader->offset;
*((void **)prog_data_out) = shader->prog_data;
return true;
}
void
crocus_init_program_cache(struct crocus_context *ice)
{
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
ice->shaders.cache =
_mesa_hash_table_create(ice, keybox_hash, keybox_equals);
ice->shaders.cache_bo =
crocus_bo_alloc(screen->bufmgr, "program_cache", 16384);
ice->shaders.cache_bo_map =
crocus_bo_map(NULL, ice->shaders.cache_bo,
MAP_READ | MAP_WRITE | MAP_ASYNC | MAP_PERSISTENT);
}
void
crocus_destroy_program_cache(struct crocus_context *ice)
{
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
ice->shaders.prog[i] = NULL;
}
if (ice->shaders.cache_bo) {
crocus_bo_unmap(ice->shaders.cache_bo);
crocus_bo_unreference(ice->shaders.cache_bo);
ice->shaders.cache_bo_map = NULL;
ice->shaders.cache_bo = NULL;
}
ralloc_free(ice->shaders.cache);
}
static const char *
cache_name(enum crocus_program_cache_id cache_id)
{
if (cache_id == CROCUS_CACHE_BLORP)
return "BLORP";
if (cache_id == CROCUS_CACHE_SF)
return "SF";
if (cache_id == CROCUS_CACHE_CLIP)
return "CLIP";
if (cache_id == CROCUS_CACHE_FF_GS)
return "FF_GS";
return _mesa_shader_stage_to_string(cache_id);
}
void
crocus_print_program_cache(struct crocus_context *ice)
{
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
const struct elk_isa_info *isa = &screen->compiler->isa;
hash_table_foreach(ice->shaders.cache, entry) {
const struct keybox *keybox = entry->key;
struct crocus_compiled_shader *shader = entry->data;
fprintf(stderr, "%s:\n", cache_name(keybox->cache_id));
elk_disassemble(isa, ice->shaders.cache_bo_map + shader->offset, 0,
shader->prog_data->program_size, NULL, stderr);
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,534 @@
/*
* Copyright 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CROCUS_RESOURCE_H
#define CROCUS_RESOURCE_H
#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "util/u_range.h"
#include "util/u_threaded_context.h"
#include "intel/isl/isl.h"
#include "intel/dev/intel_device_info.h"
#include "crocus_bufmgr.h"
struct crocus_batch;
struct crocus_context;
#define CROCUS_MAX_MIPLEVELS 15
struct crocus_format_info {
enum isl_format fmt;
enum pipe_swizzle swizzles[4];
};
static inline enum isl_channel_select
pipe_to_isl_swizzle(const enum pipe_swizzle pswz, bool green_to_blue)
{
unsigned swz = (pswz + 4) & 7;
return (green_to_blue && swz == ISL_CHANNEL_SELECT_GREEN) ? ISL_CHANNEL_SELECT_BLUE : swz;
}
static inline struct isl_swizzle
pipe_to_isl_swizzles(const enum pipe_swizzle pswz[4])
{
struct isl_swizzle swz;
swz.r = pipe_to_isl_swizzle(pswz[0], false);
swz.g = pipe_to_isl_swizzle(pswz[1], false);
swz.b = pipe_to_isl_swizzle(pswz[2], false);
swz.a = pipe_to_isl_swizzle(pswz[3], false);
return swz;
}
static inline void
crocus_combine_swizzle(enum pipe_swizzle outswz[4],
const enum pipe_swizzle fswz[4],
const enum pipe_swizzle vswz[4])
{
for (unsigned i = 0; i < 4; i++) {
switch (vswz[i]) {
case PIPE_SWIZZLE_X: outswz[i] = fswz[0]; break;
case PIPE_SWIZZLE_Y: outswz[i] = fswz[1]; break;
case PIPE_SWIZZLE_Z: outswz[i] = fswz[2]; break;
case PIPE_SWIZZLE_W: outswz[i] = fswz[3]; break;
case PIPE_SWIZZLE_1: outswz[i] = PIPE_SWIZZLE_1; break;
case PIPE_SWIZZLE_0: outswz[i] = PIPE_SWIZZLE_0; break;
default: UNREACHABLE("invalid swizzle");
}
}
}
/**
* Resources represent a GPU buffer object or image (mipmap tree).
*
* They contain the storage (BO) and layout information (ISL surface).
*/
struct crocus_resource {
struct threaded_resource base;
enum pipe_format internal_format;
/**
* The ISL surface layout information for this resource.
*
* This is not filled out for PIPE_BUFFER resources, but is guaranteed
* to be zeroed. Note that this also guarantees that res->surf.tiling
* will be ISL_TILING_LINEAR, so it's safe to check that.
*/
struct isl_surf surf;
/** Backing storage for the resource */
struct crocus_bo *bo;
/** offset at which data starts in the BO */
uint64_t offset;
/**
* A bitfield of PIPE_BIND_* indicating how this resource was bound
* in the past. Only meaningful for PIPE_BUFFER; used for flushing.
*/
unsigned bind_history;
/**
* A bitfield of MESA_SHADER_* stages indicating where this resource
* was bound.
*/
unsigned bind_stages;
/**
* For PIPE_BUFFER resources, a range which may contain valid data.
*
* This is a conservative estimate of what part of the buffer contains
* valid data that we have to preserve. The rest of the buffer is
* considered invalid, and we can promote writes to that region to
* be unsynchronized writes, avoiding blit copies.
*/
struct util_range valid_buffer_range;
/**
* Auxiliary buffer information (CCS, MCS, or HiZ).
*/
struct {
/** The surface layout for the auxiliary buffer. */
struct isl_surf surf;
/** The buffer object containing the auxiliary data. */
struct crocus_bo *bo;
/** Offset into 'bo' where the auxiliary surface starts. */
uint32_t offset;
/**
* Fast clear color for this surface. For depth surfaces, the clear
* value is stored as a float32 in the red component.
*/
union isl_color_value clear_color;
/**
* \brief The type of auxiliary compression used by this resource.
*
* This describes the type of auxiliary compression that is intended to
* be used by this resource. An aux usage of ISL_AUX_USAGE_NONE means
* that auxiliary compression is permanently disabled. An aux usage
* other than ISL_AUX_USAGE_NONE does not imply that auxiliary
* compression will always be enabled for this surface.
*/
enum isl_aux_usage usage;
/**
* \brief Maps miptree slices to their current aux state.
*
* This two-dimensional array is indexed as [level][layer] and stores an
* aux state for each slice.
*/
enum isl_aux_state **state;
/**
* If (1 << level) is set, HiZ is enabled for that miplevel.
*/
uint16_t has_hiz;
} aux;
/**
* \brief Shadow miptree for sampling when the main isn't supported by HW.
*
* To workaround various sampler bugs and limitations, we blit the main
* texture into a new texture that can be sampled.
*
* This miptree may be used for:
* - Stencil texturing (pre-BDW) as required by GL_ARB_stencil_texturing.
*/
struct crocus_resource *shadow;
bool shadow_needs_update;
/**
* For external surfaces, this is format that was used to create or import
* the surface. For internal surfaces, this will always be
* PIPE_FORMAT_NONE.
*/
enum pipe_format external_format;
/**
* For external surfaces, this is DRM format modifier that was used to
* create or import the surface. For internal surfaces, this will always
* be DRM_FORMAT_MOD_INVALID.
*/
const struct isl_drm_modifier_info *mod_info;
/**
* The screen the resource was originally created with, stored for refcounting.
*/
struct pipe_screen *orig_screen;
};
/**
* A simple <resource, offset> tuple for storing a reference to a
* piece of state stored in a GPU buffer object.
*/
struct crocus_state_ref {
struct pipe_resource *res;
uint32_t offset;
};
/**
* Gallium CSO for sampler views (texture views).
*
* In addition to the normal pipe_resource, this adds an ISL view
* which may reinterpret the format or restrict levels/layers.
*
* These can also be linear texture buffers.
*/
struct crocus_sampler_view {
struct pipe_sampler_view base;
struct isl_view view;
struct isl_view gather_view;
enum pipe_swizzle swizzle[4];
union isl_color_value clear_color;
/* A short-cut (not a reference) to the actual resource being viewed.
* Multi-planar (or depth+stencil) images may have multiple resources
* chained together; this skips having to traverse base->texture->*.
*/
struct crocus_resource *res;
};
/**
* Image view representation.
*/
struct crocus_image_view {
struct pipe_image_view base;
struct isl_view view;
};
/**
* Gallium CSO for surfaces (framebuffer attachments).
*
* A view of a surface that can be bound to a color render target or
* depth/stencil attachment.
*/
struct crocus_surface {
struct pipe_surface base;
struct isl_view view;
struct isl_view read_view;
struct isl_surf surf;
union isl_color_value clear_color;
struct pipe_resource *align_res;
};
/**
* Transfer object - information about a buffer mapping.
*/
struct crocus_transfer {
struct threaded_transfer base;
struct util_debug_callback *dbg;
void *buffer;
void *ptr;
/** A linear staging resource for GPU-based copy_region transfers. */
struct pipe_resource *staging;
struct blorp_context *blorp;
struct crocus_batch *batch;
bool dest_had_defined_contents;
bool has_swizzling;
void (*unmap)(struct crocus_transfer *);
};
/**
* Memory Object
*/
struct crocus_memory_object {
struct pipe_memory_object b;
struct crocus_bo *bo;
uint64_t format;
unsigned stride;
};
/**
* Unwrap a pipe_resource to get the underlying crocus_bo (for convenience).
*/
static inline struct crocus_bo *
crocus_resource_bo(struct pipe_resource *p_res)
{
struct crocus_resource *res = (void *) p_res;
return res->bo;
}
static inline uint32_t
crocus_mocs(const struct crocus_bo *bo,
const struct isl_device *dev)
{
return isl_mocs(dev, 0, bo && crocus_bo_is_external(bo));
}
struct crocus_format_info crocus_format_for_usage(const struct intel_device_info *,
enum pipe_format pf,
isl_surf_usage_flags_t usage);
static inline struct pipe_resource *
_crocus_resource_get_separate_stencil(struct pipe_resource *p_res)
{
/* For packed depth-stencil, we treat depth as the primary resource
* and store S8 as the "second plane" resource.
*/
if (p_res->next && p_res->next->format == PIPE_FORMAT_S8_UINT)
return p_res->next;
return NULL;
}
static inline void
crocus_get_depth_stencil_resources(const struct intel_device_info *devinfo,
struct pipe_resource *res,
struct crocus_resource **out_z,
struct crocus_resource **out_s)
{
/* gen4/5 only supports packed ds */
if (devinfo->ver < 6) {
*out_z = (void *)res;
*out_s = (void *)res;
return;
}
if (res && res->format != PIPE_FORMAT_S8_UINT) {
*out_z = (void *) res;
*out_s = (void *) _crocus_resource_get_separate_stencil(res);
} else {
*out_z = NULL;
*out_s = (void *) res;
}
}
bool crocus_resource_set_clear_color(struct crocus_context *ice,
struct crocus_resource *res,
union isl_color_value color);
union isl_color_value
crocus_resource_get_clear_color(const struct crocus_resource *res);
void
crocus_replace_buffer_storage(struct pipe_context *ctx,
struct pipe_resource *p_dst,
struct pipe_resource *p_src,
unsigned num_rebinds,
uint32_t rebind_mask,
uint32_t delete_buffer_id);
void crocus_init_screen_resource_functions(struct pipe_screen *pscreen);
void crocus_dirty_for_history(struct crocus_context *ice,
struct crocus_resource *res);
uint32_t crocus_flush_bits_for_history(struct crocus_resource *res);
void crocus_flush_and_dirty_for_history(struct crocus_context *ice,
struct crocus_batch *batch,
struct crocus_resource *res,
uint32_t extra_flags,
const char *reason);
unsigned crocus_get_num_logical_layers(const struct crocus_resource *res,
unsigned level);
void crocus_resource_disable_aux(struct crocus_resource *res);
#define INTEL_REMAINING_LAYERS UINT32_MAX
#define INTEL_REMAINING_LEVELS UINT32_MAX
void
crocus_hiz_exec(struct crocus_context *ice,
struct crocus_batch *batch,
struct crocus_resource *res,
unsigned int level, unsigned int start_layer,
unsigned int num_layers, enum isl_aux_op op);
/**
* Prepare a miptree for access
*
* This function should be called prior to any access to miptree in order to
* perform any needed resolves.
*
* \param[in] start_level The first mip level to be accessed
*
* \param[in] num_levels The number of miplevels to be accessed or
* INTEL_REMAINING_LEVELS to indicate every level
* above start_level will be accessed
*
* \param[in] start_layer The first array slice or 3D layer to be accessed
*
* \param[in] num_layers The number of array slices or 3D layers be
* accessed or INTEL_REMAINING_LAYERS to indicate
* every layer above start_layer will be accessed
*
* \param[in] aux_supported Whether or not the access will support the
* miptree's auxiliary compression format; this
* must be false for uncompressed miptrees
*
* \param[in] fast_clear_supported Whether or not the access will support
* fast clears in the miptree's auxiliary
* compression format
*/
void
crocus_resource_prepare_access(struct crocus_context *ice,
struct crocus_resource *res,
uint32_t start_level, uint32_t num_levels,
uint32_t start_layer, uint32_t num_layers,
enum isl_aux_usage aux_usage,
bool fast_clear_supported);
/**
* Complete a write operation
*
* This function should be called after any operation writes to a miptree.
* This will update the miptree's compression state so that future resolves
* happen correctly. Technically, this function can be called before the
* write occurs but the caller must ensure that they don't interlace
* crocus_resource_prepare_access and crocus_resource_finish_write calls to
* overlapping layer/level ranges.
*
* \param[in] level The mip level that was written
*
* \param[in] start_layer The first array slice or 3D layer written
*
* \param[in] num_layers The number of array slices or 3D layers
* written or INTEL_REMAINING_LAYERS to indicate
* every layer above start_layer was written
*
* \param[in] written_with_aux Whether or not the write was done with
* auxiliary compression enabled
*/
void
crocus_resource_finish_write(struct crocus_context *ice,
struct crocus_resource *res, uint32_t level,
uint32_t start_layer, uint32_t num_layers,
enum isl_aux_usage aux_usage);
/** Get the auxiliary compression state of a miptree slice */
enum isl_aux_state
crocus_resource_get_aux_state(const struct crocus_resource *res,
uint32_t level, uint32_t layer);
/**
* Set the auxiliary compression state of a miptree slice range
*
* This function directly sets the auxiliary compression state of a slice
* range of a miptree. It only modifies data structures and does not do any
* resolves. This should only be called by code which directly performs
* compression operations such as fast clears and resolves. Most code should
* use crocus_resource_prepare_access or crocus_resource_finish_write.
*/
void
crocus_resource_set_aux_state(struct crocus_context *ice,
struct crocus_resource *res, uint32_t level,
uint32_t start_layer, uint32_t num_layers,
enum isl_aux_state aux_state);
/**
* Prepare a miptree for raw access
*
* This helper prepares the miptree for access that knows nothing about any
* sort of compression whatsoever. This is useful when mapping the surface or
* using it with the blitter.
*/
static inline void
crocus_resource_access_raw(struct crocus_context *ice,
struct crocus_resource *res,
uint32_t level, uint32_t layer,
uint32_t num_layers,
bool write)
{
crocus_resource_prepare_access(ice, res, level, 1, layer, num_layers,
ISL_AUX_USAGE_NONE, false);
if (write) {
crocus_resource_finish_write(ice, res, level, layer, num_layers,
ISL_AUX_USAGE_NONE);
}
}
void
crocus_resource_get_image_offset(struct crocus_resource *res,
uint32_t level, uint32_t z,
uint32_t *x, uint32_t *y);
static inline enum isl_aux_usage
crocus_resource_texture_aux_usage(const struct crocus_resource *res)
{
return res->aux.usage == ISL_AUX_USAGE_MCS ? ISL_AUX_USAGE_MCS : ISL_AUX_USAGE_NONE;
}
void crocus_resource_prepare_texture(struct crocus_context *ice,
struct crocus_resource *res,
enum isl_format view_format,
uint32_t start_level, uint32_t num_levels,
uint32_t start_layer, uint32_t num_layers);
bool crocus_has_invalid_primary(const struct crocus_resource *res,
unsigned start_level, unsigned num_levels,
unsigned start_layer, unsigned num_layers);
void crocus_resource_check_level_layer(const struct crocus_resource *res,
uint32_t level, uint32_t layer);
bool crocus_resource_level_has_hiz(const struct crocus_resource *res,
uint32_t level);
bool crocus_has_color_unresolved(const struct crocus_resource *res,
unsigned start_level, unsigned num_levels,
unsigned start_layer, unsigned num_layers);
bool crocus_render_formats_color_compatible(enum isl_format a,
enum isl_format b,
union isl_color_value color);
enum isl_aux_usage crocus_resource_render_aux_usage(struct crocus_context *ice,
struct crocus_resource *res,
uint32_t level,
enum isl_format render_fmt,
bool draw_aux_disabled);
void crocus_resource_prepare_render(struct crocus_context *ice,
struct crocus_resource *res, uint32_t level,
uint32_t start_layer, uint32_t layer_count,
enum isl_aux_usage aux_usage);
void crocus_resource_finish_render(struct crocus_context *ice,
struct crocus_resource *res, uint32_t level,
uint32_t start_layer, uint32_t layer_count,
enum isl_aux_usage aux_usage);
#endif
+723
View File
@@ -0,0 +1,723 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* @file crocus_screen.c
*
* Screen related driver hooks and capability lists.
*
* A program may use multiple rendering contexts (crocus_context), but
* they all share a common screen (crocus_screen). Global driver state
* can be stored in the screen; it may be accessed by multiple threads.
*/
#include <stdio.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/os_misc.h"
#include "util/u_debug.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "util/u_transfer_helper.h"
#include "util/u_upload_mgr.h"
#include "util/ralloc.h"
#include "util/xmlconfig.h"
#include "drm-uapi/i915_drm.h"
#include "crocus_context.h"
#include "crocus_defines.h"
#include "crocus_fence.h"
#include "crocus_perf.h"
#include "crocus_pipe.h"
#include "crocus_resource.h"
#include "crocus_screen.h"
#include "intel/compiler/elk/elk_compiler.h"
#include "intel/common/intel_debug_identifier.h"
#include "intel/common/intel_gem.h"
#include "intel/common/intel_l3_config.h"
#include "intel/common/intel_uuid.h"
#include "crocus_monitor.h"
#define genX_call(devinfo, func, ...) \
switch ((devinfo)->verx10) { \
case 80: \
gfx8_##func(__VA_ARGS__); \
break; \
case 75: \
gfx75_##func(__VA_ARGS__); \
break; \
case 70: \
gfx7_##func(__VA_ARGS__); \
break; \
case 60: \
gfx6_##func(__VA_ARGS__); \
break; \
case 50: \
gfx5_##func(__VA_ARGS__); \
break; \
case 45: \
gfx45_##func(__VA_ARGS__); \
break; \
case 40: \
gfx4_##func(__VA_ARGS__); \
break; \
default: \
UNREACHABLE("Unknown hardware generation"); \
}
static const char *
crocus_get_vendor(struct pipe_screen *pscreen)
{
return "Intel";
}
static const char *
crocus_get_device_vendor(struct pipe_screen *pscreen)
{
return "Intel";
}
static void
crocus_get_device_uuid(struct pipe_screen *pscreen, char *uuid)
{
struct crocus_screen *screen = (struct crocus_screen *)pscreen;
intel_uuid_compute_device_id((uint8_t *)uuid, &screen->devinfo, PIPE_UUID_SIZE);
}
static void
crocus_get_driver_uuid(struct pipe_screen *pscreen, char *uuid)
{
struct crocus_screen *screen = (struct crocus_screen *)pscreen;
const struct intel_device_info *devinfo = &screen->devinfo;
intel_uuid_compute_driver_id((uint8_t *)uuid, devinfo, PIPE_UUID_SIZE);
}
static const char *
crocus_get_name(struct pipe_screen *pscreen)
{
struct crocus_screen *screen = (struct crocus_screen *)pscreen;
const struct intel_device_info *devinfo = &screen->devinfo;
static char buf[128];
snprintf(buf, sizeof(buf), "Mesa %s", devinfo->name);
return buf;
}
static uint64_t
get_aperture_size(int fd)
{
struct drm_i915_gem_get_aperture aperture = {};
intel_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
return aperture.aper_size;
}
static void
crocus_init_shader_caps(struct crocus_screen *screen)
{
const struct intel_device_info *devinfo = &screen->devinfo;
for (unsigned i = 0; i <= MESA_SHADER_COMPUTE; i++) {
struct pipe_shader_caps *caps =
(struct pipe_shader_caps *)&screen->base.shader_caps[i];
if (devinfo->ver < 6 &&
i != MESA_SHADER_VERTEX &&
i != MESA_SHADER_FRAGMENT)
continue;
if (devinfo->ver == 6 &&
i != MESA_SHADER_VERTEX &&
i != MESA_SHADER_FRAGMENT &&
i != MESA_SHADER_GEOMETRY)
continue;
caps->max_instructions = i == MESA_SHADER_FRAGMENT ? 1024 : 16384;
caps->max_alu_instructions =
caps->max_tex_instructions =
caps->max_tex_indirections = i == MESA_SHADER_FRAGMENT ? 1024 : 0;
caps->max_control_flow_depth = UINT_MAX;
/* Gen7 vec4 geom backend */
caps->max_inputs = i == MESA_SHADER_VERTEX || i == MESA_SHADER_GEOMETRY ? 16 : 32;
caps->max_outputs = 32;
caps->max_const_buffer0_size = 16 * 1024 * sizeof(float);
caps->max_const_buffers = devinfo->ver >= 6 ? 16 : 1;
caps->max_temps = 256; /* GL_MAX_PROGRAM_TEMPORARIES_ARB */
/* Lie about these to avoid st/mesa's GLSL IR lowering of indirects,
* which we don't want. Our compiler backend will check elk_compiler's
* options and call nir_lower_indirect_derefs_to_if_else_trees
* appropriately anyway.
*/
caps->indirect_temp_addr = true;
caps->indirect_const_addr = true;
caps->integers = true;
caps->max_texture_samplers =
caps->max_sampler_views =
(devinfo->ver >= 7) ? CROCUS_MAX_TEXTURE_SAMPLERS : 16;
if (devinfo->ver >= 7 &&
(i == MESA_SHADER_FRAGMENT || i == MESA_SHADER_COMPUTE))
caps->max_shader_images = CROCUS_MAX_TEXTURE_SAMPLERS;
caps->max_shader_buffers =
devinfo->ver >= 7 ? (CROCUS_MAX_ABOS + CROCUS_MAX_SSBOS) : 0;
caps->supported_irs = 1 << PIPE_SHADER_IR_NIR;
}
}
static void
crocus_init_compute_caps(struct crocus_screen *screen)
{
struct pipe_compute_caps *caps =
(struct pipe_compute_caps *)&screen->base.compute_caps;
const struct intel_device_info *devinfo = &screen->devinfo;
if (devinfo->ver < 7)
return;
const uint32_t max_invocations = 32 * devinfo->max_cs_workgroup_threads;
caps->address_bits = 32;
caps->grid_dimension = 3;
caps->max_grid_size[0] =
caps->max_grid_size[1] =
caps->max_grid_size[2] = 65535;
/* MaxComputeWorkGroupSize[0..2] */
caps->max_block_size[0] =
caps->max_block_size[1] =
caps->max_block_size[2] = max_invocations;
/* MaxComputeWorkGroupInvocations */
caps->max_threads_per_block = max_invocations;
/* MaxComputeSharedMemorySize */
caps->max_local_size = 64 * 1024;
caps->subgroup_sizes = ELK_SUBGROUP_SIZE;
caps->max_variable_threads_per_block = max_invocations;
}
static void
crocus_init_screen_caps(struct crocus_screen *screen)
{
const struct intel_device_info *devinfo = &screen->devinfo;
struct pipe_caps *caps = (struct pipe_caps *)&screen->base.caps;
u_init_pipe_screen_caps(&screen->base, 1);
caps->prefer_real_buffer_in_constbuf0 = true;
caps->npot_textures = true;
caps->anisotropic_filter = true;
caps->occlusion_query = true;
caps->texture_swizzle = true;
caps->texture_mirror_clamp_to_edge = true;
caps->blend_equation_separate = true;
caps->fragment_shader_texture_lod = true;
caps->fragment_shader_derivatives = true;
caps->primitive_restart = true;
caps->primitive_restart_fixed_index = true;
caps->indep_blend_enable = true;
caps->fs_coord_origin_upper_left = true;
caps->fs_coord_pixel_center_integer = true;
caps->depth_clip_disable = true;
caps->vs_instanceid = true;
caps->vertex_element_instance_divisor = true;
caps->seamless_cube_map = true;
caps->seamless_cube_map_per_texture = true;
caps->conditional_render = true;
caps->texture_barrier = true;
caps->vertex_color_unclamped = true;
caps->start_instance = true;
caps->force_persample_interp = true;
caps->mixed_framebuffer_sizes = true;
caps->vs_layer_viewport = true;
caps->tes_layer_viewport = true;
caps->uma = true;
caps->clip_halfz = true;
caps->tgsi_texcoord = true;
caps->device_reset_status_query = true;
caps->copy_between_compressed_and_plain_formats = true;
caps->signed_vertex_buffer_offset = true;
caps->texture_float_linear = true;
caps->texture_half_float_linear = true;
caps->polygon_offset_clamp = true;
caps->multisample_z_resolve = true;
caps->shader_group_vote = true;
caps->vs_window_space_position = true;
caps->texture_gather_sm5 = true;
caps->shader_array_components = true;
caps->glsl_tess_levels_as_inputs = true;
caps->fs_position_is_sysval = true;
caps->fs_face_is_integer_sysval = true;
caps->invalidate_buffer = true;
caps->surface_no_compress = true;
caps->surface_reinterpret_blocks = true;
caps->fence_signal = true;
caps->demote_to_helper_invocation = true;
caps->gl_clamp = true;
caps->legacy_math_rules = true;
caps->native_fence_fd = true;
caps->int64 =
caps->shader_ballot =
caps->packed_uniforms = devinfo->ver == 8;
caps->quads_follow_provoking_vertex_convention = devinfo->ver <= 5;
caps->texture_query_lod =
caps->query_time_elapsed = devinfo->ver >= 5;
caps->draw_indirect =
caps->multi_draw_indirect =
caps->multi_draw_indirect_params =
caps->framebuffer_no_attachment =
caps->fs_fine_derivative =
caps->stream_output_interleave_buffers =
caps->shader_clock =
caps->texture_query_samples =
caps->compute =
caps->sampler_view_target =
caps->shader_samples_identical =
caps->shader_pack_half_float =
caps->gl_spirv =
caps->gl_spirv_variable_pointers =
caps->compute_shader_derivatives =
caps->doubles =
caps->memobj =
caps->image_store_formatted =
caps->alpha_to_coverage_dither_control = devinfo->ver >= 7;
caps->query_buffer_object =
caps->robust_buffer_access_behavior = devinfo->ver >= 7;
caps->cull_distance =
caps->query_pipeline_statistics_single =
caps->stream_output_pause_resume =
caps->sample_shading =
caps->cube_map_array =
caps->query_so_overflow =
caps->texture_multisample =
caps->conditional_render_inverted =
caps->query_timestamp =
caps->texture_buffer_objects =
caps->indep_blend_func =
caps->texture_shadow_lod =
caps->load_constbuf =
caps->draw_parameters =
caps->clear_scissored = devinfo->ver >= 6;
caps->fbfetch = devinfo->verx10 >= 45 ? ELK_MAX_DRAW_BUFFERS : 0;
/* in theory CL (965gm) can do this */
caps->max_dual_source_render_targets = devinfo->verx10 >= 45 ? 1 : 0;
caps->max_render_targets = ELK_MAX_DRAW_BUFFERS;
caps->max_texture_2d_size = devinfo->ver >= 7 ? 16384 : 8192;
caps->max_texture_cube_levels = devinfo->ver >= 7 ?
CROCUS_MAX_MIPLEVELS /* 16384x16384 */ : CROCUS_MAX_MIPLEVELS - 1; /* 8192x8192 */
caps->max_texture_3d_levels = 12; /* 2048x2048 */
caps->max_stream_output_buffers = (devinfo->ver >= 6) ? 4 : 0;
caps->max_texture_array_layers = devinfo->ver >= 7 ? 2048 : 512;
caps->max_stream_output_separate_components =
ELK_MAX_SOL_BINDINGS / CROCUS_MAX_SOL_BUFFERS;
caps->max_stream_output_interleaved_components = ELK_MAX_SOL_BINDINGS;
caps->glsl_feature_level_compatibility =
caps->glsl_feature_level = devinfo->ver >= 7 ? 460 :
(devinfo->ver >= 6 ? 330 : 140);
caps->clip_planes = devinfo->verx10 < 45 ? 6 : 1; // defaults to MAX (8)
/* 3DSTATE_CONSTANT_XS requires the start of UBOs to be 32B aligned */
caps->constant_buffer_offset_alignment = 32;
caps->min_map_buffer_alignment = CROCUS_MAP_BUFFER_ALIGNMENT;
caps->shader_buffer_offset_alignment = devinfo->ver >= 7 ? 4 : 0;
caps->max_shader_buffer_size = devinfo->ver >= 7 ? (1 << 27) : 0;
caps->texture_buffer_offset_alignment = 16; // XXX: u_screen says 256 is the minimum value...
caps->texture_transfer_modes = PIPE_TEXTURE_TRANSFER_BLIT;
caps->max_texel_buffer_elements = CROCUS_MAX_TEXTURE_BUFFER_SIZE;
caps->max_viewports = devinfo->ver >= 6 ? 16 : 1;
caps->max_geometry_output_vertices = devinfo->ver >= 6 ? 256 : 0;
caps->max_geometry_total_output_components = devinfo->ver >= 6 ? 1024 : 0;
caps->max_gs_invocations = devinfo->ver >= 7 ? 32 : 1;
caps->max_texture_gather_components = devinfo->ver >= 7 ? 4 :
(devinfo->ver == 6 ? 1 : 0);
caps->min_texture_gather_offset = devinfo->ver >= 7 ? -32 :
(devinfo->ver == 6 ? -8 : 0);
caps->max_texture_gather_offset = devinfo->ver >= 7 ? 31 :
(devinfo->ver == 6 ? 7 : 0);
caps->max_vertex_streams = devinfo->ver >= 7 ? 4 : 1;
caps->vendor_id = 0x8086;
caps->device_id = screen->pci_id;
/* Once a batch uses more than 75% of the maximum mappable size, we
* assume that there's some fragmentation, and we start doing extra
* flushing, etc. That's the big cliff apps will care about.
*/
const unsigned gpu_mappable_megabytes =
(screen->aperture_threshold) / (1024 * 1024);
uint64_t system_memory_bytes =
os_get_gpu_heap_size(screen->driconf.heap_memory_percent, NULL);
if (!system_memory_bytes) {
caps->video_memory = -1;
} else {
const unsigned system_memory_megabytes =
(unsigned) (system_memory_bytes / (1024 * 1024));
caps->video_memory = MIN2(system_memory_megabytes, gpu_mappable_megabytes);
}
caps->max_shader_patch_varyings =
caps->max_varyings = (screen->devinfo.ver >= 6) ? 32 : 16;
/* AMD_pinned_memory assumes the flexibility of using client memory
* for any buffer (incl. vertex buffers) which rules out the prospect
* of using snooped buffers, as using snooped buffers without
* cogniscience is likely to be detrimental to performance and require
* extensive checking in the driver for correctness, e.g. to prevent
* illegal snoop <-> snoop transfers.
*/
caps->resource_from_user_memory = devinfo->has_llc && devinfo->has_userptr_uapi;
caps->throttle = !screen->driconf.disable_throttling;
caps->context_priority_mask =
PIPE_CONTEXT_PRIORITY_LOW |
PIPE_CONTEXT_PRIORITY_MEDIUM |
PIPE_CONTEXT_PRIORITY_HIGH;
/* Let mesa/st lower for us */
caps->flatshade = false;
caps->frontend_noop = true;
// XXX: don't hardcode 00:00:02.0 PCI here
caps->pci_group = 0;
caps->pci_bus = 0;
caps->pci_device = 2;
caps->pci_function = 0;
caps->hardware_gl_select = false;
caps->timer_resolution = DIV_ROUND_UP(1000000000ull, devinfo->timestamp_frequency);
caps->min_line_width =
caps->min_line_width_aa =
caps->min_point_size =
caps->min_point_size_aa = 1;
caps->point_size_granularity =
caps->line_width_granularity = 0.1;
caps->max_line_width =
caps->max_line_width_aa = devinfo->ver >= 6 ? 7.375f : 7.0f;
caps->max_point_size =
caps->max_point_size_aa = 255.0f;
caps->max_texture_anisotropy = 16.0f;
caps->max_texture_lod_bias = 15.0f;
}
static uint64_t
crocus_get_timestamp(struct pipe_screen *pscreen)
{
struct crocus_screen *screen = (struct crocus_screen *) pscreen;
uint64_t result;
if (!intel_gem_read_render_timestamp(crocus_bufmgr_get_fd(screen->bufmgr),
screen->devinfo.kmd_type, &result))
return 0;
result = intel_device_info_timebase_scale(&screen->devinfo, result);
result &= (1ull << TIMESTAMP_BITS) - 1;
return result;
}
void
crocus_screen_destroy(struct crocus_screen *screen)
{
intel_perf_free(screen->perf_cfg);
u_transfer_helper_destroy(screen->base.transfer_helper);
crocus_bufmgr_unref(screen->bufmgr);
disk_cache_destroy(screen->disk_cache);
intel_virtio_unref_fd(screen->winsys_fd);
close(screen->winsys_fd);
ralloc_free(screen);
}
static void
crocus_screen_unref(struct pipe_screen *pscreen)
{
crocus_pscreen_unref(pscreen);
}
static void
crocus_query_memory_info(struct pipe_screen *pscreen,
struct pipe_memory_info *info)
{
}
static int
crocus_get_compute_param(struct pipe_screen *pscreen,
enum pipe_shader_ir ir_type,
enum pipe_compute_cap param,
void *ret)
{
struct crocus_screen *screen = (struct crocus_screen *) pscreen;
const struct intel_device_info *devinfo = &screen->devinfo;
switch (param) {
case PIPE_COMPUTE_CAP_MAX_COMPUTE_UNITS:
if (ret) {
uint32_t num_eu = devinfo->num_eu_total > 0 ? devinfo->num_eu_total : ((devinfo->gt == 2) ? 16 : 6);
((uint32_t *)ret)[0] = num_eu;
}
return sizeof(uint32_t);
case PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK:
if (ret)
((uint64_t *)ret)[0] = 1024;
return sizeof(uint64_t);
case PIPE_COMPUTE_CAP_MAX_GRID_SIZE:
if (ret) {
((uint64_t *)ret)[0] = 65535;
((uint64_t *)ret)[1] = 65535;
((uint64_t *)ret)[2] = 65535;
}
return 3 * sizeof(uint64_t);
case PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE:
if (ret) {
((uint64_t *)ret)[0] = 1024;
((uint64_t *)ret)[1] = 1024;
((uint64_t *)ret)[2] = 1024;
}
return 3 * sizeof(uint64_t);
case PIPE_COMPUTE_CAP_PREFERRED_BLOCK_SIZE:
if (ret)
((uint64_t *)ret)[0] = 256;
return sizeof(uint64_t);
case PIPE_COMPUTE_CAP_IMAGES_SUPPORTED:
if (ret)
((uint32_t *)ret)[0] = 1;
return sizeof(uint32_t);
case PIPE_COMPUTE_CAP_SUBGROUP_SIZE:
if (ret)
((uint32_t *)ret)[0] = devinfo->subgroup_size ? devinfo->subgroup_size : 16;
return sizeof(uint32_t);
default:
return 0;
}
}
static struct disk_cache *
crocus_get_disk_shader_cache(struct pipe_screen *pscreen)
{
struct crocus_screen *screen = (struct crocus_screen *) pscreen;
return screen->disk_cache;
}
static const struct intel_l3_config *
crocus_get_default_l3_config(const struct intel_device_info *devinfo,
bool compute)
{
bool wants_dc_cache = true;
bool has_slm = compute;
const struct intel_l3_weights w =
intel_get_default_l3_weights(devinfo, wants_dc_cache, has_slm);
return intel_get_l3_config(devinfo, w);
}
static void
crocus_shader_debug_log(void *data, unsigned *id, const char *fmt, ...)
{
struct util_debug_callback *dbg = data;
va_list args;
if (!dbg->debug_message)
return;
va_start(args, fmt);
dbg->debug_message(dbg->data, id, UTIL_DEBUG_TYPE_SHADER_INFO, fmt, args);
va_end(args);
}
static void
crocus_shader_perf_log(void *data, unsigned *id, const char *fmt, ...)
{
struct util_debug_callback *dbg = data;
va_list args;
va_start(args, fmt);
if (INTEL_DEBUG(DEBUG_PERF)) {
va_list args_copy;
va_copy(args_copy, args);
vfprintf(stderr, fmt, args_copy);
va_end(args_copy);
}
if (dbg->debug_message) {
dbg->debug_message(dbg->data, id, UTIL_DEBUG_TYPE_PERF_INFO, fmt, args);
}
va_end(args);
}
static int
crocus_screen_get_fd(struct pipe_screen *pscreen)
{
struct crocus_screen *screen = (struct crocus_screen *)pscreen;
return screen->winsys_fd;
}
struct pipe_screen *
crocus_screen_create(int fd, const struct pipe_screen_config *config)
{
struct crocus_screen *screen = rzalloc(NULL, struct crocus_screen);
if (!screen)
return NULL;
if (intel_virtio_init_fd(fd) < 0)
return NULL;
if (!intel_get_device_info_from_fd(fd, &screen->devinfo, 4, 8))
return NULL;
screen->pci_id = screen->devinfo.pci_device_id;
if (screen->devinfo.ver > 8)
return NULL;
if (screen->devinfo.ver == 8) {
/* bind to cherryview or bdw if forced */
if (screen->devinfo.platform != INTEL_PLATFORM_CHV &&
!os_get_option("CROCUS_GEN8"))
return NULL;
}
p_atomic_set(&screen->refcount, 1);
screen->aperture_bytes = get_aperture_size(fd);
screen->aperture_threshold = screen->aperture_bytes * 3 / 4;
driParseConfigFiles(config->options, config->options_info,
&(driConfigFileParseParams) { .driverName = "crocus" });
bool bo_reuse = false;
int bo_reuse_mode = driQueryOptioni(config->options, "bo_reuse");
switch (bo_reuse_mode) {
case DRI_CONF_BO_REUSE_DISABLED:
break;
case DRI_CONF_BO_REUSE_ALL:
bo_reuse = true;
break;
}
screen->bufmgr = crocus_bufmgr_get_for_fd(&screen->devinfo, fd, bo_reuse);
if (!screen->bufmgr)
return NULL;
screen->fd = crocus_bufmgr_get_fd(screen->bufmgr);
screen->winsys_fd = fd;
process_intel_debug_variable();
screen->driconf.dual_color_blend_by_location =
driQueryOptionb(config->options, "dual_color_blend_by_location");
screen->driconf.disable_throttling =
driQueryOptionb(config->options, "disable_throttling");
screen->driconf.always_flush_cache =
driQueryOptionb(config->options, "always_flush_cache");
screen->driconf.limit_trig_input_range =
driQueryOptionb(config->options, "limit_trig_input_range");
screen->driconf.lower_depth_range_rate =
driQueryOptionf(config->options, "lower_depth_range_rate");
screen->driconf.heap_memory_percent =
driQueryOptionf(config->options, "heap_memory_percent");
if (screen->driconf.heap_memory_percent == OS_GPU_HEAP_SIZE_HEURISTIC)
screen->driconf.heap_memory_percent = 1.0f;
screen->precompile = debug_get_bool_option("shader_precompile", true);
isl_device_init(&screen->isl_dev, &screen->devinfo);
screen->compiler = elk_compiler_create(screen, &screen->devinfo);
screen->compiler->shader_debug_log = crocus_shader_debug_log;
screen->compiler->shader_perf_log = crocus_shader_perf_log;
screen->compiler->supports_shader_constants = false;
screen->compiler->constant_buffer_0_is_relative = true;
if (screen->devinfo.ver >= 7) {
screen->l3_config_3d = crocus_get_default_l3_config(&screen->devinfo, false);
screen->l3_config_cs = crocus_get_default_l3_config(&screen->devinfo, true);
}
crocus_disk_cache_init(screen);
slab_create_parent(&screen->transfer_pool,
sizeof(struct crocus_transfer), 64);
struct pipe_screen *pscreen = &screen->base;
crocus_init_screen_fence_functions(pscreen);
crocus_init_screen_resource_functions(pscreen);
for (unsigned i = 0; i <= MESA_SHADER_COMPUTE; i++)
pscreen->nir_options[i] = screen->compiler->nir_options[i];
pscreen->destroy = crocus_screen_unref;
pscreen->get_name = crocus_get_name;
pscreen->get_vendor = crocus_get_vendor;
pscreen->get_device_vendor = crocus_get_device_vendor;
pscreen->get_screen_fd = crocus_screen_get_fd;
pscreen->get_device_uuid = crocus_get_device_uuid;
pscreen->get_driver_uuid = crocus_get_driver_uuid;
pscreen->get_disk_shader_cache = crocus_get_disk_shader_cache;
pscreen->is_format_supported = crocus_is_format_supported;
pscreen->context_create = crocus_create_context;
pscreen->get_timestamp = crocus_get_timestamp;
pscreen->query_memory_info = crocus_query_memory_info;
pscreen->get_driver_query_group_info = crocus_get_monitor_group_info;
pscreen->get_driver_query_info = crocus_get_monitor_info;
pscreen->get_compute_param = crocus_get_compute_param;
crocus_init_shader_caps(screen);
crocus_init_compute_caps(screen);
crocus_init_screen_caps(screen);
genX_call(&screen->devinfo, crocus_init_screen_state, screen);
genX_call(&screen->devinfo, crocus_init_screen_query, screen);
return pscreen;
}
+255
View File
@@ -0,0 +1,255 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CROCUS_SCREEN_H
#define CROCUS_SCREEN_H
#include "pipe/p_screen.h"
#include "pipe/p_state.h"
#include "frontend/drm_driver.h"
#include "util/disk_cache.h"
#include "util/slab.h"
#include "util/u_screen.h"
#include "intel/dev/intel_device_info.h"
#include "intel/dev/virtio/intel_virtio.h"
#include "intel/isl/isl.h"
#include "crocus_bufmgr.h"
#include "compiler/shader_enums.h"
struct crocus_resource;
struct crocus_context;
struct crocus_sampler_state;
struct intel_vue_map;
struct elk_tcs_prog_key;
struct elk_tes_prog_key;
struct elk_cs_prog_key;
struct elk_fs_prog_key;
struct elk_vs_prog_key;
struct elk_gs_prog_key;
struct shader_info;
#define READ_ONCE(x) (*(volatile __typeof__(x) *)&(x))
#define WRITE_ONCE(x, v) *(volatile __typeof__(x) *)&(x) = (v)
#define CROCUS_MAX_TEXTURE_SAMPLERS 32
#define CROCUS_MAX_SOL_BUFFERS 4
#define CROCUS_MAP_BUFFER_ALIGNMENT 64
/**
* Virtual table for generation-specific (genxml) function calls.
*/
struct crocus_vtable {
void (*destroy_state)(struct crocus_context *ice);
void (*init_render_context)(struct crocus_batch *batch);
void (*init_compute_context)(struct crocus_batch *batch);
void (*upload_render_state)(struct crocus_context *ice,
struct crocus_batch *batch,
const struct pipe_draw_info *draw,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *sc);
void (*update_surface_base_address)(struct crocus_batch *batch);
void (*upload_compute_state)(struct crocus_context *ice,
struct crocus_batch *batch,
const struct pipe_grid_info *grid);
void (*rebind_buffer)(struct crocus_context *ice,
struct crocus_resource *res);
void (*resolve_conditional_render)(struct crocus_context *ice);
void (*emit_compute_predicate)(struct crocus_batch *batch);
void (*load_register_reg32)(struct crocus_batch *batch, uint32_t dst,
uint32_t src);
void (*load_register_reg64)(struct crocus_batch *batch, uint32_t dst,
uint32_t src);
void (*load_register_imm32)(struct crocus_batch *batch, uint32_t reg,
uint32_t val);
void (*load_register_imm64)(struct crocus_batch *batch, uint32_t reg,
uint64_t val);
void (*load_register_mem32)(struct crocus_batch *batch, uint32_t reg,
struct crocus_bo *bo, uint32_t offset);
void (*load_register_mem64)(struct crocus_batch *batch, uint32_t reg,
struct crocus_bo *bo, uint32_t offset);
void (*store_register_mem32)(struct crocus_batch *batch, uint32_t reg,
struct crocus_bo *bo, uint32_t offset,
bool predicated);
void (*store_register_mem64)(struct crocus_batch *batch, uint32_t reg,
struct crocus_bo *bo, uint32_t offset,
bool predicated);
void (*store_data_imm32)(struct crocus_batch *batch,
struct crocus_bo *bo, uint32_t offset,
uint32_t value);
void (*store_data_imm64)(struct crocus_batch *batch,
struct crocus_bo *bo, uint32_t offset,
uint64_t value);
void (*copy_mem_mem)(struct crocus_batch *batch,
struct crocus_bo *dst_bo, uint32_t dst_offset,
struct crocus_bo *src_bo, uint32_t src_offset,
unsigned bytes);
void (*emit_raw_pipe_control)(struct crocus_batch *batch,
const char *reason, uint32_t flags,
struct crocus_bo *bo, uint32_t offset,
uint64_t imm);
void (*emit_mi_report_perf_count)(struct crocus_batch *batch,
struct crocus_bo *bo,
uint32_t offset_in_bytes,
uint32_t report_id);
uint32_t *(*create_so_decl_list)(const struct pipe_stream_output_info *sol,
const struct intel_vue_map *vue_map);
void (*populate_vs_key)(const struct crocus_context *ice,
const struct shader_info *info,
mesa_shader_stage last_stage,
struct elk_vs_prog_key *key);
void (*populate_tcs_key)(const struct crocus_context *ice,
struct elk_tcs_prog_key *key);
void (*populate_tes_key)(const struct crocus_context *ice,
const struct shader_info *info,
mesa_shader_stage last_stage,
struct elk_tes_prog_key *key);
void (*populate_gs_key)(const struct crocus_context *ice,
const struct shader_info *info,
mesa_shader_stage last_stage,
struct elk_gs_prog_key *key);
void (*populate_fs_key)(const struct crocus_context *ice,
const struct shader_info *info,
struct elk_fs_prog_key *key);
void (*populate_cs_key)(const struct crocus_context *ice,
struct elk_cs_prog_key *key);
void (*fill_clamp_mask)(const struct crocus_sampler_state *state,
int s,
uint32_t *clamp_mask);
void (*lost_genx_state)(struct crocus_context *ice, struct crocus_batch *batch);
void (*finish_batch)(struct crocus_batch *batch); /* haswell only */
void (*upload_urb_fence)(struct crocus_batch *batch); /* gen4/5 only */
bool (*blit_blt)(struct crocus_batch *batch,
const struct pipe_blit_info *info);
bool (*copy_region_blt)(struct crocus_batch *batch,
struct crocus_resource *dst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct crocus_resource *src,
unsigned src_level,
const struct pipe_box *src_box);
bool (*calculate_urb_fence)(struct crocus_batch *batch, unsigned csize,
unsigned vsize, unsigned sfsize);
void (*batch_reset_dirty)(struct crocus_batch *batch);
unsigned (*translate_prim_type)(enum mesa_prim prim, uint8_t verts_per_patch);
void (*update_so_strides)(struct crocus_context *ice,
uint16_t *strides);
uint32_t (*get_so_offset)(struct pipe_stream_output_target *tgt);
};
struct crocus_screen {
struct pipe_screen base;
uint32_t refcount;
/** Global slab allocator for crocus_transfer_map objects */
struct slab_parent_pool transfer_pool;
/** drm device file descriptor, shared with bufmgr, do not close. */
int fd;
/**
* drm device file descriptor to used for window system integration, owned
* by iris_screen, can be a different DRM instance than fd.
*/
int winsys_fd;
/** PCI ID for our GPU device */
int pci_id;
struct crocus_vtable vtbl;
/** Global program_string_id counter (see get_program_string_id()) */
unsigned program_id;
/** Precompile shaders at link time? (Can be disabled for debugging.) */
bool precompile;
/** driconf options and application workarounds */
struct {
/** Dual color blend by location instead of index (for broken apps) */
bool dual_color_blend_by_location;
bool disable_throttling;
bool always_flush_cache;
bool limit_trig_input_range;
float lower_depth_range_rate;
float heap_memory_percent;
} driconf;
uint64_t aperture_bytes;
uint64_t aperture_threshold;
struct intel_device_info devinfo;
struct isl_device isl_dev;
struct crocus_bufmgr *bufmgr;
struct elk_compiler *compiler;
struct intel_perf_config *perf_cfg;
const struct intel_l3_config *l3_config_3d;
const struct intel_l3_config *l3_config_cs;
struct disk_cache *disk_cache;
};
struct pipe_screen *
crocus_screen_create(int fd, const struct pipe_screen_config *config);
void crocus_screen_destroy(struct crocus_screen *screen);
UNUSED static inline struct pipe_screen *
crocus_pscreen_ref(struct pipe_screen *pscreen)
{
struct crocus_screen *screen = (struct crocus_screen *) pscreen;
p_atomic_inc(&screen->refcount);
return pscreen;
}
UNUSED static inline void
crocus_pscreen_unref(struct pipe_screen *pscreen)
{
struct crocus_screen *screen = (struct crocus_screen *) pscreen;
if (p_atomic_dec_zero(&screen->refcount))
crocus_screen_destroy(screen);
}
bool
crocus_is_format_supported(struct pipe_screen *pscreen,
enum pipe_format format,
enum pipe_texture_target target,
unsigned sample_count,
unsigned storage_sample_count,
unsigned usage);
void crocus_disk_cache_init(struct crocus_screen *screen);
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,16 @@
Quick TODO list from what I can see:
General:
Re-emit SURFACE_STATE_BASE_ADDRESS at the top of every batch
Gen4:
rgb32 issue
Gen5:
rgb32 issue
Gen6:
vec4 push constants
Gen7:
@@ -0,0 +1,20 @@
// crocus specific driconf options
DRI_CONF_SECTION_DEBUG
DRI_CONF_DUAL_COLOR_BLEND_BY_LOCATION(false)
DRI_CONF_DISABLE_THROTTLING(false)
DRI_CONF_ALWAYS_FLUSH_CACHE(false)
DRI_CONF_LIMIT_TRIG_INPUT_RANGE(false)
DRI_CONF_SECTION_END
DRI_CONF_SECTION_PERFORMANCE
DRI_CONF_OPT_E(bo_reuse, 1, 0, 1, "Buffer object reuse",)
DRI_CONF_SECTION_END
DRI_CONF_SECTION_QUALITY
DRI_CONF_PP_LOWER_DEPTH_RANGE_RATE()
DRI_CONF_SECTION_END
DRI_CONF_SECTION_MISCELLANEOUS
DRI_CONF_HEAP_MEMORY_PERCENT(1.0f)
DRI_CONF_SECTION_END
@@ -0,0 +1,190 @@
/*
* Copyright © 2016 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
static inline struct blorp_address
dynamic_state_address(struct blorp_batch *blorp_batch, uint32_t offset)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return (struct blorp_address) {
.buffer = batch->state.bo,
.offset = offset,
};
}
static inline struct blorp_address
instruction_state_address(struct blorp_batch *blorp_batch, uint32_t offset)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
return (struct blorp_address) {
.buffer = batch->ice->shaders.cache_bo,
.offset = offset,
};
}
static struct blorp_address
blorp_emit_vs_state(struct blorp_batch *blorp_batch)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
uint32_t offset;
blorp_emit_dynamic(blorp_batch, GENX(VS_STATE), vs, 64, &offset) {
vs.Enable = false;
vs.URBEntryAllocationSize = batch->ice->urb.vsize - 1;
#if GFX_VER == 5
vs.NumberofURBEntries = batch->ice->urb.nr_vs_entries >> 2;
#else
vs.NumberofURBEntries = batch->ice->urb.nr_vs_entries;
#endif
}
return dynamic_state_address(blorp_batch, offset);
}
static struct blorp_address
blorp_emit_sf_state(struct blorp_batch *blorp_batch,
const struct blorp_params *params)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
const struct elk_sf_prog_data *prog_data = params->sf_prog_data;
uint32_t offset;
blorp_emit_dynamic(blorp_batch, GENX(SF_STATE), sf, 64, &offset) {
#if GFX_VER == 4
sf.KernelStartPointer =
instruction_state_address(blorp_batch, params->sf_prog_kernel);
#else
sf.KernelStartPointer = params->sf_prog_kernel;
#endif
sf.GRFRegisterCount = DIV_ROUND_UP(prog_data->total_grf, 16) - 1;
sf.VertexURBEntryReadLength = prog_data->urb_read_length;
sf.VertexURBEntryReadOffset = ELK_SF_URB_ENTRY_READ_OFFSET;
sf.DispatchGRFStartRegisterForURBData = 3;
sf.URBEntryAllocationSize = batch->ice->urb.sfsize - 1;
sf.NumberofURBEntries = batch->ice->urb.nr_sf_entries;
#if GFX_VER == 5
sf.MaximumNumberofThreads = MIN2(48, batch->ice->urb.nr_sf_entries) - 1;
#else
sf.MaximumNumberofThreads = MIN2(24, batch->ice->urb.nr_sf_entries) - 1;
#endif
sf.ViewportTransformEnable = false;
sf.CullMode = CULLMODE_NONE;
}
return dynamic_state_address(blorp_batch, offset);
}
static struct blorp_address
blorp_emit_wm_state(struct blorp_batch *blorp_batch,
const struct blorp_params *params)
{
const struct elk_fs_prog_data *prog_data = params->fs_prog_data;
uint32_t offset;
blorp_emit_dynamic(blorp_batch, GENX(WM_STATE), wm, 64, &offset) {
if (params->src.enabled) {
/* Iron Lake can't do sampler prefetch */
wm.SamplerCount = (GFX_VER != 5);
wm.BindingTableEntryCount = 2;
uint32_t sampler = blorp_emit_sampler_state(blorp_batch);
wm.SamplerStatePointer = dynamic_state_address(blorp_batch, sampler);
}
if (prog_data) {
wm.DispatchGRFStartRegisterForConstantSetupData0 =
prog_data->base.dispatch_grf_start_reg;
wm.SetupURBEntryReadLength = prog_data->num_varying_inputs * 2;
wm.SetupURBEntryReadOffset = 0;
wm.DepthCoefficientURBReadOffset = 1;
wm.PixelShaderKillsPixel = prog_data->uses_kill;
wm.ThreadDispatchEnable = true;
wm.EarlyDepthTestEnable = true;
wm._8PixelDispatchEnable = prog_data->dispatch_8;
wm._16PixelDispatchEnable = prog_data->dispatch_16;
wm._32PixelDispatchEnable = prog_data->dispatch_32;
#if GFX_VER == 4
wm.KernelStartPointer0 =
instruction_state_address(blorp_batch, params->wm_prog_kernel);
wm.GRFRegisterCount0 = elk_fs_prog_data_reg_blocks(prog_data, wm, 0);
#else
wm.KernelStartPointer0 = params->wm_prog_kernel +
elk_fs_prog_data_prog_offset(prog_data, wm, 0);
wm.KernelStartPointer1 = params->wm_prog_kernel +
elk_fs_prog_data_prog_offset(prog_data, wm, 1);
wm.KernelStartPointer2 = params->wm_prog_kernel +
elk_fs_prog_data_prog_offset(prog_data, wm, 2);
wm.GRFRegisterCount0 = elk_fs_prog_data_reg_blocks(prog_data, wm, 0);
wm.GRFRegisterCount1 = elk_fs_prog_data_reg_blocks(prog_data, wm, 1);
wm.GRFRegisterCount2 = elk_fs_prog_data_reg_blocks(prog_data, wm, 2);
#endif
}
wm.MaximumNumberofThreads =
blorp_batch->blorp->compiler->elk->devinfo->max_wm_threads - 1;
}
return dynamic_state_address(blorp_batch, offset);
}
static struct blorp_address
blorp_emit_color_calc_state(struct blorp_batch *blorp_batch)
{
uint32_t cc_viewport = blorp_emit_cc_viewport(blorp_batch);
uint32_t offset;
blorp_emit_dynamic(blorp_batch, GENX(COLOR_CALC_STATE), cc, 64, &offset) {
cc.CCViewportStatePointer = dynamic_state_address(blorp_batch, cc_viewport);
}
return dynamic_state_address(blorp_batch, offset);
}
static void
blorp_emit_pipeline(struct blorp_batch *blorp_batch,
const struct blorp_params *params)
{
struct crocus_batch *batch = blorp_batch->driver_batch;
emit_urb_config(blorp_batch, params);
blorp_emit(blorp_batch, GENX(3DSTATE_PIPELINED_POINTERS), pp) {
pp.PointertoVSState = blorp_emit_vs_state(blorp_batch);
pp.GSEnable = false;
pp.ClipEnable = false;
pp.PointertoSFState = blorp_emit_sf_state(blorp_batch, params);
pp.PointertoWMState = blorp_emit_wm_state(blorp_batch, params);
pp.PointertoColorCalcState = blorp_emit_color_calc_state(blorp_batch);
}
batch->screen->vtbl.upload_urb_fence(batch);
blorp_emit(blorp_batch, GENX(CS_URB_STATE), curb);
blorp_emit(blorp_batch, GENX(CONSTANT_BUFFER), curb);
}
+81
View File
@@ -0,0 +1,81 @@
# Copyright © 2017-2019 Intel Corporation
# SPDX-License-Identifier: MIT
files_libcrocus = files(
'gen4_blorp_exec.h',
'driinfo_crocus.h',
'crocus_batch.c',
'crocus_batch.h',
'crocus_blit.c',
'crocus_bufmgr.c',
'crocus_bufmgr.h',
'crocus_clear.c',
'crocus_context.c',
'crocus_context.h',
'crocus_draw.c',
'crocus_fence.c',
'crocus_fence.h',
'crocus_fine_fence.c',
'crocus_fine_fence.h',
'crocus_formats.c',
'crocus_genx_macros.h',
'crocus_genx_protos.h',
'crocus_monitor.c',
'crocus_perf.c',
'crocus_perf.h',
'crocus_performance_query.c',
'crocus_pipe.h',
'crocus_pipe_control.c',
'crocus_program.c',
'crocus_program_cache.c',
'crocus_resolve.c',
'crocus_resource.c',
'crocus_resource.h',
'crocus_screen.c',
'crocus_screen.h',
'crocus_disk_cache.c',
)
crocus_per_hw_ver_libs = []
foreach v : ['40', '45', '50', '60', '70', '75', '80']
crocus_per_hw_ver_libs += static_library(
'crocus_per_hw_ver@0@'.format(v),
['crocus_blorp.c', 'crocus_query.c', 'crocus_state.c', 'crocus_blt.c', gen_xml_pack],
include_directories : [inc_include, inc_src, inc_mesa, inc_gallium, inc_gallium_aux, inc_intel],
c_args : [
no_override_init_args, sse2_args,
'-DGFX_VERx10=@0@'.format(v),
],
gnu_symbol_visibility : 'hidden',
dependencies : [dep_libdrm, dep_valgrind, idep_mesautil, idep_genxml, idep_nir_headers, idep_intel_dev, idep_intel_blorp_elk],
)
endforeach
libcrocus = static_library(
'crocus',
[files_libcrocus, gen_xml_pack],
include_directories : [
inc_src, inc_include, inc_gallium, inc_gallium_aux, inc_intel,
inc_gallium_drivers,
# these should not be necessary, but main/macros.h...
inc_mesa
],
c_args : [sse2_args],
cpp_args : [sse2_args],
gnu_symbol_visibility : 'hidden',
dependencies : [
dep_libdrm, dep_valgrind, idep_genxml, idep_mesautil,
idep_libintel_common, idep_nir_headers,
idep_intel_dev, idep_intel_blorp_elk, idep_intel_decoder_elk,
idep_intel_compiler_elk,
],
link_with : [
crocus_per_hw_ver_libs, libisl,
libintel_perf
],
)
driver_crocus = declare_dependency(
compile_args : '-DGALLIUM_CROCUS',
link_with : [libcrocus, libcrocuswinsys],
)
+63
View File
@@ -0,0 +1,63 @@
BasedOnStyle: InheritParentConfig
DisableFormat: false
ColumnLimit: 120
SortIncludes: Never
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
AlignTrailingComments: true
PenaltyExcessCharacter: 75
AlwaysBreakTemplateDeclarations: Yes
BreakConstructorInitializers: BeforeColon
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 3
IndentCaseLabels: true
BreakBeforeTernaryOperators: false
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterEnum: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
FixNamespaceComments: true
KeepEmptyLinesAtTheStartOfBlocks: true
AlwaysBreakAfterReturnType: TopLevel
BinPackArguments: false
BinPackParameters: false
Cpp11BracedListStyle: false
SpaceAfterCStyleCast: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpacesInContainerLiterals: true
SpaceBeforeParens: ControlStatements
SpacesBeforeTrailingComments: 3
SpacesInAngles: Never
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpacesInCStyleCastParentheses: false
SpaceAfterLogicalNot: false
SpaceBeforeAssignmentOperators: true
SpaceInEmptyParentheses: false
SpaceInEmptyBlock: true
MaxEmptyLinesToKeep: 3
@@ -0,0 +1,10 @@
# Tessellation isoline tests are flaky on WARP, probably a WARP bug
isoline
isoline-no-tcs
# If the test machine are busy, these can spuriously fail
arb_timer_query
ext_timer_query
# assertion failure in https://gitlab.freedesktop.org/mesa/mesa/-/jobs/48717501
spec@arb_compute_shader@execution@simple-barrier-atomics
@@ -0,0 +1,5 @@
[[piglit]]
piglit_folder = "C:/piglit"
profile = "quick_gl"
process_isolation = true
timeout = 240
@@ -0,0 +1,410 @@
# from https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25931
spec@arb_internalformat_query2@image_format_compatibility_type pname checks,Fail
spec@arb_internalformat_query2@image_format_compatibility_type pname checks@GL_IMAGE_FORMAT_COMPATIBILITY_TYPE,Fail
spec@arb_internalformat_query2@max dimensions related pname checks,Fail
spec@arb_internalformat_query2@max dimensions related pname checks@GL_MAX_COMBINED_DIMENSIONS,Fail
spec@arb_internalformat_query2@max dimensions related pname checks@GL_MAX_DEPTH,Fail
spec@arb_internalformat_query2@max dimensions related pname checks@GL_MAX_HEIGHT,Fail
spec@arb_internalformat_query2@max dimensions related pname checks@GL_MAX_LAYERS,Fail
spec@arb_internalformat_query2@max dimensions related pname checks@GL_MAX_WIDTH,Fail
spec@!opengl [email protected],Fail
spec@!opengl [email protected]@glFlush,Fail
spec@!opengl [email protected],Fail
spec@!opengl [email protected],Fail
spec@!opengl 1.0@rasterpos,Fail
spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail
spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail
spec@!opengl 1.1@line-smooth-coverage,Fail
spec@!opengl 1.1@line-smooth-stipple,Fail
spec@!opengl 1.1@linestipple,Fail
spec@!opengl 1.1@linestipple@Factor 2x,Fail
spec@!opengl 1.1@linestipple@Factor 3x,Fail
spec@!opengl 1.1@linestipple@Line loop,Fail
spec@!opengl 1.1@linestipple@Line strip,Fail
spec@!opengl 1.1@linestipple@Restarting lines within a single Begin-End block,Fail
spec@!opengl 1.1@polygon-mode-offset,Fail
spec@!opengl 1.1@polygon-mode-offset@config 4: Expected white pixel on bottom edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 4: Expected white pixel on left edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 4: Expected white pixel on right edge,Fail
spec@!opengl 1.1@polygon-mode-offset@config 4: Expected white pixel on top edge,Fail
spec@!opengl 1.1@polygon-offset,Fail
spec@!opengl 1.1@windowoverlap,Missing
spec@!opengl 3.0@sampler-cube-shadow,Fail
spec@!opengl 3.1@default-vao,Fail
spec@!opengl 3.1@genned-names,Fail
spec@!opengl [email protected],Fail
spec@!opengl [email protected],Fail
spec@!opengl [email protected] cull-back pv-last,Fail
spec@!opengl [email protected] cull-front pv-last,Fail
spec@!opengl [email protected] line cull-back pv-last,Fail
spec@!opengl [email protected] line cull-front pv-last,Fail
spec@!opengl [email protected] pv-last,Fail
spec@arb_draw_indirect@arb_draw_indirect-api-errors,Crash
spec@arb_framebuffer_object@fbo-blit-scaled-linear,Fail
spec@arb_get_program_binary@restore-sso-program,Fail
spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex,Fail
spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex@'vs_input2' on GL_PROGRAM_INPUT,Fail
spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex@'vs_input2[1][0]' on GL_PROGRAM_INPUT,Fail
spec@arb_sample_shading@arb_sample_shading-builtin-gl-sample-mask-mrt-alpha-to-coverage,Fail
spec@arb_seamless_cube_map@arb_seamless_cubemap,Fail
spec@arb_separate_shader_objects@rendezvous by location (5 stages),Crash
spec@arb_shader_atomic_counters@semantics,Fail
spec@arb_shader_atomic_counters@semantics@Tessellation control shader atomic built-in semantics,Fail
spec@arb_texture_cube_map_array@arb_texture_cube_map_array-sampler-cube-array-shadow,Fail
spec@arb_texture_rg@texwrap formats-int,Fail
spec@arb_texture_rg@texwrap formats-int offset,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R16I,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R16I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R16I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R16UI,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R16UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R16UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R32I,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R32I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R32I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R32UI,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R32UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R32UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R8I,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R8I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R8I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R8UI,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R8UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_R8UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG16I,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG16I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG16I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG16UI,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG16UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG16UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG32I,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG32I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG32I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG32UI,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG32UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG32UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG8I,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG8I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG8I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG8UI,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG8UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int offset@GL_RG8UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R16I,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R16I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R16I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R16UI,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R16UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R16UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R32I,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R32I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R32I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R32UI,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R32UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R32UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R8I,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R8I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R8I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R8UI,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R8UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_R8UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG16I,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG16I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG16I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG16UI,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG16UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG16UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG32I,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG32I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG32I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG32UI,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG32UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG32UI- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG8I,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG8I- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG8I- swizzled,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG8UI,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG8UI- NPOT,Fail
spec@arb_texture_rg@texwrap formats-int@GL_RG8UI- swizzled,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats offset,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats offset@GL_RGB10_A2UI,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats offset@GL_RGB10_A2UI- NPOT,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats offset@GL_RGB10_A2UI- swizzled,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats@GL_RGB10_A2UI,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats@GL_RGB10_A2UI- NPOT,Fail
spec@arb_texture_rgb10_a2ui@texwrap formats@GL_RGB10_A2UI- swizzled,Fail
spec@arb_texture_stencil8@texwrap formats,Fail
spec@arb_texture_stencil8@texwrap formats offset,Fail
spec@arb_texture_stencil8@texwrap formats offset@GL_STENCIL_INDEX8,Fail
spec@arb_texture_stencil8@texwrap formats offset@GL_STENCIL_INDEX8- NPOT,Fail
spec@arb_texture_stencil8@texwrap formats offset@GL_STENCIL_INDEX8- swizzled,Fail
spec@arb_texture_stencil8@texwrap formats@GL_STENCIL_INDEX8,Fail
spec@arb_texture_stencil8@texwrap formats@GL_STENCIL_INDEX8- NPOT,Fail
spec@arb_texture_stencil8@texwrap formats@GL_STENCIL_INDEX8- swizzled,Fail
spec@arb_transform_feedback_instanced@draw-auto instanced,Fail
spec@arb_vertex_program@arb_vertex_program-matrix-property-bindings,Fail
spec@ext_framebuffer_multisample@accuracy 16 srgb depthstencil,Fail
spec@ext_framebuffer_multisample@accuracy 16 srgb depthstencil linear,Fail
spec@ext_framebuffer_multisample@accuracy 16 srgb small depthstencil,Fail
spec@ext_framebuffer_multisample@accuracy 16 srgb small depthstencil linear,Fail
spec@ext_framebuffer_multisample@accuracy all_samples srgb depthstencil,Fail
spec@ext_framebuffer_multisample@accuracy all_samples srgb depthstencil linear,Fail
spec@ext_framebuffer_multisample@accuracy all_samples srgb small depthstencil,Fail
spec@ext_framebuffer_multisample@accuracy all_samples srgb small depthstencil linear,Fail
spec@ext_framebuffer_multisample@alpha-to-one-dual-src-blend 16,Fail
spec@ext_framebuffer_multisample@alpha-to-one-dual-src-blend 2,Fail
spec@ext_framebuffer_multisample@alpha-to-one-dual-src-blend 4,Fail
spec@ext_framebuffer_multisample@alpha-to-one-dual-src-blend 6,Fail
spec@ext_framebuffer_multisample@alpha-to-one-dual-src-blend 8,Fail
spec@ext_framebuffer_multisample@draw-buffers-alpha-to-one 16,Fail
spec@ext_framebuffer_multisample@draw-buffers-alpha-to-one 2,Fail
spec@ext_framebuffer_multisample@draw-buffers-alpha-to-one 4,Fail
spec@ext_framebuffer_multisample@draw-buffers-alpha-to-one 6,Fail
spec@ext_framebuffer_multisample@draw-buffers-alpha-to-one 8,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-one 16,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-one 2,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-one 4,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-one 6,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-one 8,Fail
spec@ext_texture_integer@texwrap formats,Fail
spec@ext_texture_integer@texwrap formats offset,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA16I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA32I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA8I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_ALPHA8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY16I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY32I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY8I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_INTENSITY8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE16I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE32I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE8I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA16I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA32I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA8I_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_LUMINANCE_ALPHA8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB16I,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB16I- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB16I- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB16UI,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB16UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB16UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB32I,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB32I- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB32I- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB32UI,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB32UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB32UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB8I,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB8I- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB8I- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB8UI,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB8UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGB8UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA16I,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA16I- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA16I- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA16UI,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA16UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA16UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA32I,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA32I- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA32I- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA32UI,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA32UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA32UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA8I,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA8I- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA8I- swizzled,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA8UI,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA8UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats offset@GL_RGBA8UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA16I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA32I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA8I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_ALPHA8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY16I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY32I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY8I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_INTENSITY8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE16I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE32I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE8I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA16I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA16I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA16I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA16UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA16UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA16UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA32I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA32I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA32I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA32UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA32UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA32UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA8I_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA8I_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA8I_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA8UI_EXT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA8UI_EXT- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_LUMINANCE_ALPHA8UI_EXT- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB16I,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB16I- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB16I- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB16UI,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB16UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB16UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB32I,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB32I- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB32I- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB32UI,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB32UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB32UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB8I,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB8I- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB8I- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB8UI,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB8UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGB8UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA16I,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA16I- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA16I- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA16UI,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA16UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA16UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA32I,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA32I- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA32I- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA32UI,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA32UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA32UI- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA8I,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA8I- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA8I- swizzled,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA8UI,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA8UI- NPOT,Fail
spec@ext_texture_integer@texwrap formats@GL_RGBA8UI- swizzled,Fail
spec@ext_transform_feedback@points-large,Fail
spec@ext_transform_feedback@tessellation polygon wireframe,Fail
spec@ext_transform_feedback@tessellation quad_strip wireframe,Fail
spec@ext_transform_feedback@tessellation quads wireframe,Fail
spec@ext_transform_feedback@tessellation triangle_strip flat_last,Fail
[email protected]@[email protected],Fail
[email protected]@execution@geometry@primitive-types gl_triangle_strip,Fail
[email protected]@execution@geometry@primitive-types gl_triangle_strip_adjacency,Fail
[email protected]@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip ffs,Fail
[email protected]@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip other,Fail
[email protected]@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip_adjacency ffs,Fail
[email protected]@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip_adjacency other,Fail
[email protected]@gs-max-output,Crash
spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail
spec@khr_texture_compression_astc@miptree-gl srgb-fp@sRGB decode full precision,Fail
spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp,Fail
spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp@sRGB decode full precision,Fail
spec@nv_copy_depth_to_color@nv_copy_depth_to_color,Fail
spec@nv_copy_depth_to_color@nv_copy_depth_to_color 0 0x223344ff,Fail
spec@nv_copy_depth_to_color@nv_copy_depth_to_color 0 0x76356278,Fail
spec@nv_copy_depth_to_color@nv_copy_depth_to_color 1 0x223344ff,Fail
spec@nv_copy_depth_to_color@nv_copy_depth_to_color 1 0x76356278,Fail
wgl@wgl-multi-context-single-window,Fail
@@ -0,0 +1,5 @@
[[piglit]]
piglit_folder = "C:/piglit"
profile = "quick_shader"
process_isolation = true
timeout = 240
@@ -0,0 +1,25 @@
spec@arb_gpu_shader_int64@execution@indirect-array-two-accesses,Fail
spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-07,Fail
spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-cumulative,Fail
spec@arb_tessellation_shader@execution@gs-primitiveid-instanced,Fail
spec@arb_tessellation_shader@execution@tcs-output-unmatched,Fail
spec@arb_tessellation_shader@execution@tes-primitiveid,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-patch-output-array-vec4-index-wr,Crash
spec@arb_tessellation_shader@execution@variable-indexing@tcs-patch-vec4-index-wr,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-patch-vec4-swiz-index-wr,Fail
[email protected]@execution@geometry@primitive-id-out,Fail
[email protected]@execution@primitive-id-no-gs-quad-strip,Fail
[email protected]@execution@primitive-id-no-gs-quads,Fail
[email protected]@execution@primitive-id-no-gs-point,Fail
[email protected]@execution@variable-indexing@gs-output-array-vec4-index-wr,Crash
# These tests use a TCS output variable only as temporary storage. Since the output
# is unused by the TES, we remove it.
spec@arb_tessellation_shader@execution@barrier-patch,Crash
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-float-index-wr-before-barrier,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-vec2-index-rd-after-barrier,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-vec2-index-wr-before-barrier,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-vec3-index-rd-after-barrier,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-vec3-index-wr-before-barrier,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-vec4-index-rd-after-barrier,Fail
spec@arb_tessellation_shader@execution@variable-indexing@tcs-output-array-vec4-index-wr-before-barrier,Fail
@@ -0,0 +1,37 @@
# The Windows piglit build doesn't produce any EGL/GLES tests
gles
opengl es
egl
glsl-es
spec@oes
# These are GLES extensions
ext_clear_texture
ext_disjoint_timer_query
ext_draw_instanced
ext_occlusion_query_boolean
ext_render_snorm
ext_texture_format_bgra8888
ext_texture_norm16
ext_unpack_subimage
# These are Vulkan tests which aren't built on Windows either
ext_external_objects@vk
# Linux-specific extension
ext_image_dma_buf_import
# Requires EGL/GLES
shaders@glsl-bug-110796
amd_compressed_atc_texture
intel_performance_query
# This test will timeout and slows down the whole job, so just skip it
spec@arb_tessellation_shader@arb_tessellation_shader-tes-gs-max-output
[email protected]@gs-max-output
# The > symbol in a test name causes the log to be unable to be written
>
# This test requires glut
windowoverlap
@@ -0,0 +1,43 @@
.d3d12-test:
extends:
- .use-windows_test_msvc
- .glon12-test-rules
stage: layered-backends
dependencies:
- windows-msvc
needs:
- job: windows-msvc
- job: windows_test_msvc
optional: true
variables:
GIT_STRATEGY: none # testing doesn't build anything from source
GALLIUM_DRIVER: d3d12
DRIVER_NAME: d3d12
WGL_DISABLE_ERROR_DIALOGS: "true"
D3D12_AGILITY_RELATIVE_PATH: "D3D12\\"
D3D12_AGILITY_SDK_VERSION: 619
.d3d12-test-piglit:
extends:
- .d3d12-test
- .test-piglit
script:
- . _install/piglit_run.ps1
# temporarily restrict to GSt runners until we discover why GL testing is
# so slow on the Microsoft runners
tags:
- windows
- docker
- "2022"
- mesa
- gstreamer-windows
timeout: 12m
artifacts:
when: on_failure
name: "${CI_PROJECT_NAME}_${CI_JOB_NAME_SLUG}"
paths:
- logs/
variables:
PIGLIT_SKIPS: d3d12-skips.txt
PIGLIT_FLAKES: d3d12-flakes.txt
@@ -0,0 +1,22 @@
include:
- local: 'src/gallium/drivers/d3d12/ci/gitlab-ci-inc.yml'
test-d3d12-quick_gl:
extends:
- .d3d12-test-piglit
variables:
PIGLIT_SUITE: d3d12-quick_gl.toml
PIGLIT_BASELINE: d3d12-quick_gl.txt
test-d3d12-quick_shader:
extends:
- .d3d12-test-piglit
variables:
PIGLIT_SUITE: d3d12-quick_shader.toml
PIGLIT_BASELINE: d3d12-quick_shader.txt
test-d3d12-vainfo:
extends:
- .d3d12-test
script:
- . _install/vainfo_run.ps1
+529
View File
@@ -0,0 +1,529 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_batch.h"
#include "d3d12_context.h"
#include "d3d12_fence.h"
#include "d3d12_query.h"
#include "d3d12_residency.h"
#include "d3d12_resource.h"
#include "d3d12_resource_state.h"
#include "d3d12_screen.h"
#include "d3d12_surface.h"
#include "util/hash_table.h"
#include "util/set.h"
#include "util/u_inlines.h"
#include <dxguids/dxguids.h>
unsigned d3d12_sampler_desc_table_key_hash(const void* key)
{
const d3d12_sampler_desc_table_key* table = (d3d12_sampler_desc_table_key*)key;
return _mesa_hash_data(table->descs, sizeof(table->descs[0]) * table->count);
}
bool d3d12_sampler_desc_table_key_equals(const void* a, const void* b)
{
const d3d12_sampler_desc_table_key* table_a = (d3d12_sampler_desc_table_key*)a;
const d3d12_sampler_desc_table_key* table_b = (d3d12_sampler_desc_table_key*)b;
return table_a->count == table_b->count && memcmp(table_a->descs, table_b->descs, sizeof(table_a->descs[0]) * table_a->count) == 0;
}
bool
d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
batch->bos = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
batch->local_bos = UTIL_DYNARRAY_INIT;
batch->local_bo_pending = UTIL_DYNARRAY_INIT;
batch->bos_pending = UTIL_DYNARRAY_INIT;
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
batch->surfaces = _mesa_set_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
batch->objects = _mesa_set_create(NULL,
_mesa_hash_pointer,
_mesa_key_pointer_equal);
if (!batch->bos || !batch->objects)
return false;
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if (!batch->surfaces)
return false;
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
batch->queries = _mesa_set_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
batch->view_heap =
d3d12_descriptor_heap_new(screen->dev,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
8096);
batch->sampler_tables = _mesa_hash_table_create(NULL, d3d12_sampler_desc_table_key_hash,
d3d12_sampler_desc_table_key_equals);
batch->sampler_views = _mesa_set_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
if (!batch->sampler_tables || !batch->sampler_views || !batch->view_heap || !batch->queries)
return false;
batch->zombie_samplers = UTIL_DYNARRAY_INIT;
batch->sampler_heap =
d3d12_descriptor_heap_new(screen->dev,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
1024);
if (!batch->sampler_heap)
return false;
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
if (FAILED(screen->dev->CreateCommandAllocator(screen->queue_type,
IID_PPV_ARGS(&batch->cmdalloc))))
return false;
return true;
}
static inline void
delete_bo(d3d12_bo *bo)
{
d3d12_bo_unreference(bo);
}
static void
delete_bo_entry(hash_entry *entry)
{
struct d3d12_bo *bo = (struct d3d12_bo *)entry->key;
d3d12_bo_unreference(bo);
}
static void
delete_sampler_view_table(hash_entry *entry)
{
FREE((void*)entry->key);
FREE(entry->data);
}
static void
delete_sampler_view(set_entry *entry)
{
struct pipe_sampler_view *pres = (struct pipe_sampler_view *)entry->key;
pipe_sampler_view_reference(&pres, NULL);
}
static void
delete_object(set_entry *entry)
{
ID3D12Object *object = (ID3D12Object *)entry->key;
object->Release();
}
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
static void
delete_query(set_entry *entry)
{
struct d3d12_query *query = (struct d3d12_query *)entry->key;
if (pipe_reference(&query->reference, nullptr))
d3d12_destroy_query(query);
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
bool
d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t timeout_ns)
{
// batch hasn't been submitted before
if (!batch->fence && !batch->has_errors)
return true;
if (batch->fence) {
if (!d3d12_fence_finish(batch->fence, timeout_ns))
return false;
d3d12_fence_reference(&batch->fence, NULL);
}
_mesa_hash_table_clear(batch->bos, delete_bo_entry);
util_dynarray_foreach(&batch->bos_pending, struct d3d12_pending_free_entry*, entry)
FREE(*entry);
util_dynarray_clear(&batch->bos_pending);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
set_foreach_remove(batch->surfaces, entry) {
struct pipe_surface *surf = (struct pipe_surface *)entry->key;
pipe_surface_reference(&surf, NULL, &ctx->base, d3d12_surface_destroy);
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
_mesa_set_clear(batch->objects, delete_object);
util_dynarray_foreach(&batch->local_bos, d3d12_bo*, bo) {
(*bo)->local_reference_mask[batch->ctx_id] &= ~(1 << batch->ctx_index);
delete_bo(*bo);
}
util_dynarray_clear(&batch->local_bos);
util_dynarray_foreach(&batch->local_bo_pending, struct d3d12_pending_free_entry*, entry)
FREE(*entry);
util_dynarray_clear(&batch->local_bo_pending);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if (d3d12_screen(ctx->base.screen)->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
_mesa_hash_table_clear(batch->sampler_tables, delete_sampler_view_table);
_mesa_set_clear(batch->sampler_views, delete_sampler_view);
_mesa_set_clear(batch->queries, delete_query);
util_dynarray_foreach(&batch->zombie_samplers, d3d12_descriptor_handle, handle)
d3d12_descriptor_handle_free(handle);
util_dynarray_clear(&batch->zombie_samplers);
d3d12_descriptor_heap_clear(batch->view_heap);
d3d12_descriptor_heap_clear(batch->sampler_heap);
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
if (FAILED(batch->cmdalloc->Reset())) {
debug_printf("D3D12: resetting ID3D12CommandAllocator failed\n");
return false;
}
batch->has_errors = false;
batch->pending_memory_barrier = false;
return true;
}
void
d3d12_destroy_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
d3d12_reset_batch(ctx, batch, OS_TIMEOUT_INFINITE);
batch->cmdalloc->Release();
_mesa_hash_table_destroy(batch->bos, NULL);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if (d3d12_screen(ctx->base.screen)->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
d3d12_descriptor_heap_free(batch->sampler_heap);
d3d12_descriptor_heap_free(batch->view_heap);
_mesa_hash_table_destroy(batch->sampler_tables, NULL);
_mesa_set_destroy(batch->sampler_views, NULL);
_mesa_set_destroy(batch->queries, NULL);
util_dynarray_fini(&batch->zombie_samplers);
}
_mesa_set_destroy(batch->surfaces, NULL);
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
_mesa_set_destroy(batch->objects, NULL);
util_dynarray_fini(&batch->local_bos);
util_dynarray_fini(&batch->local_bo_pending);
util_dynarray_fini(&batch->bos_pending);
}
void
d3d12_start_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
d3d12_reset_batch(ctx, batch, OS_TIMEOUT_INFINITE);
/* Create or reset global command list */
if (ctx->cmdlist) {
if (FAILED(ctx->cmdlist->Reset(batch->cmdalloc, NULL))) {
debug_printf("D3D12: resetting ID3D12GraphicsCommandList failed\n");
batch->has_errors = true;
return;
}
} else {
if (FAILED(screen->dev->CreateCommandList(0, screen->queue_type,
batch->cmdalloc, NULL,
IID_PPV_ARGS(&ctx->cmdlist)))) {
debug_printf("D3D12: creating ID3D12GraphicsCommandList failed\n");
batch->has_errors = true;
return;
}
if (FAILED(ctx->cmdlist->QueryInterface(IID_PPV_ARGS(&ctx->cmdlist2)))) {
ctx->cmdlist2 = nullptr;
}
if (FAILED(ctx->cmdlist->QueryInterface(IID_PPV_ARGS(&ctx->cmdlist8)))) {
ctx->cmdlist8 = nullptr;
}
}
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
ID3D12DescriptorHeap* heaps[2] = { d3d12_descriptor_heap_get(batch->view_heap),
d3d12_descriptor_heap_get(batch->sampler_heap) };
ctx->cmdlist->SetDescriptorHeaps(2, heaps);
ctx->cmdlist_dirty = ~0;
for (int i = 0; i < MESA_SHADER_STAGES; ++i)
ctx->shader_dirty[i] = ~0;
if (!ctx->queries_disabled)
d3d12_resume_queries(ctx);
if (ctx->current_predication)
d3d12_enable_predication(ctx);
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
batch->submit_id = ++ctx->submit_id;
}
void
d3d12_end_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if (!ctx->queries_disabled)
d3d12_suspend_queries(ctx);
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
if (FAILED(ctx->cmdlist->Close())) {
debug_printf("D3D12: closing ID3D12GraphicsCommandList failed\n");
batch->has_errors = true;
return;
}
mtx_lock(&screen->submit_mutex);
#ifndef _GAMING_XBOX
d3d12_process_batch_residency(screen, batch);
#endif
bool has_state_fixup = d3d12_context_state_resolve_submission(ctx, batch);
ID3D12CommandList *cmdlists[] = { ctx->state_fixup_cmdlist, ctx->cmdlist };
ID3D12CommandList **to_execute = cmdlists;
UINT count_to_execute = ARRAY_SIZE(cmdlists);
if (!has_state_fixup) {
to_execute++;
count_to_execute--;
}
screen->cmdqueue->ExecuteCommandLists(count_to_execute, to_execute);
batch->fence = d3d12_create_fence(screen, true);
if (batch->fence) {
uint64_t fv = batch->fence->value;
unsigned n_local = util_dynarray_num_elements(&batch->local_bo_pending,
struct d3d12_pending_free_entry*);
struct d3d12_pending_free_entry **local_entries =
(struct d3d12_pending_free_entry **)util_dynarray_begin(&batch->local_bo_pending);
bool local_ok = n_local > 0;
for (unsigned i = 0; i < n_local; ++i) {
if (!local_entries[i]) {
local_ok = false;
break;
}
}
unsigned n_shared = util_dynarray_num_elements(&batch->bos_pending,
struct d3d12_pending_free_entry*);
struct d3d12_pending_free_entry **shared_entries =
(struct d3d12_pending_free_entry **)util_dynarray_begin(&batch->bos_pending);
bool shared_ok = n_shared > 0;
for (unsigned i = 0; i < n_shared; ++i) {
if (!shared_entries[i]) {
shared_ok = false;
break;
}
}
if (local_ok || shared_ok) {
mtx_lock(&screen->pending_free_lock);
if (local_ok) {
for (unsigned i = 0; i < n_local; ++i) {
local_entries[i]->fence_value = fv;
list_addtail(&local_entries[i]->link, &screen->pending_free_list);
}
}
if (shared_ok) {
for (unsigned i = 0; i < n_shared; ++i) {
shared_entries[i]->fence_value = fv;
list_addtail(&shared_entries[i]->link, &screen->pending_free_list);
}
}
mtx_unlock(&screen->pending_free_lock);
}
if (local_ok) {
struct d3d12_bo **bos =
(struct d3d12_bo **)util_dynarray_begin(&batch->local_bos);
for (unsigned i = 0; i < n_local; ++i)
bos[i]->local_reference_mask[batch->ctx_id] &= ~(1 << batch->ctx_index);
util_dynarray_clear(&batch->local_bos);
util_dynarray_clear(&batch->local_bo_pending);
}
if (shared_ok) {
_mesa_hash_table_clear(batch->bos, NULL);
util_dynarray_clear(&batch->bos_pending);
}
}
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
/* batch->queries is NULL when no grfx supported */
if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
set_foreach_remove(batch->queries, entry) {
d3d12_query *query = (struct d3d12_query *)entry->key;
if (pipe_reference(&query->reference, nullptr))
d3d12_destroy_query(query);
else
query->fence_value = screen->fence_value;
}
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
mtx_unlock(&screen->submit_mutex);
d3d12_screen_reclaim_completed(screen);
}
inline uint8_t*
d3d12_batch_get_reference(struct d3d12_batch *batch,
struct d3d12_bo *bo)
{
if (batch->ctx_id != D3D12_CONTEXT_NO_ID) {
if ((bo->local_reference_mask[batch->ctx_id] & (1 << batch->ctx_index)) != 0) {
return &bo->local_reference_state[batch->ctx_id][batch->ctx_index];
}
else
return NULL;
}
else {
hash_entry* entry = _mesa_hash_table_search(batch->bos, bo);
if (entry == NULL)
return NULL;
else
return (uint8_t*)&entry->data;
}
}
inline uint8_t*
d3d12_batch_acquire_reference(struct d3d12_batch *batch,
struct d3d12_bo *bo)
{
if (batch->ctx_id != D3D12_CONTEXT_NO_ID) {
if ((bo->local_reference_mask[batch->ctx_id] & (1 << batch->ctx_index)) == 0) {
d3d12_bo_reference(bo);
util_dynarray_append(&batch->local_bos, bo);
struct d3d12_pending_free_entry *entry = MALLOC_STRUCT(d3d12_pending_free_entry);
if (entry)
entry->bo = bo;
util_dynarray_append(&batch->local_bo_pending, entry);
bo->local_reference_mask[batch->ctx_id] |= (1 << batch->ctx_index);
bo->local_reference_state[batch->ctx_id][batch->ctx_index] = batch_bo_reference_none;
}
return &bo->local_reference_state[batch->ctx_id][batch->ctx_index];
}
else {
hash_entry* entry = _mesa_hash_table_search(batch->bos, bo);
if (entry == NULL) {
d3d12_bo_reference(bo);
entry = _mesa_hash_table_insert(batch->bos, bo, NULL);
struct d3d12_pending_free_entry *pe = MALLOC_STRUCT(d3d12_pending_free_entry);
if (pe)
pe->bo = bo;
util_dynarray_append(&batch->bos_pending, pe);
}
return (uint8_t*)&entry->data;
}
}
bool
d3d12_batch_has_references(struct d3d12_batch *batch,
struct d3d12_bo *bo,
bool want_to_write)
{
uint8_t*state = d3d12_batch_get_reference(batch, bo);
if (state == NULL)
return false;
bool resource_was_written = ((batch_bo_reference_state)(size_t)*state & batch_bo_reference_written) != 0;
return want_to_write || resource_was_written;
}
void
d3d12_batch_reference_resource(struct d3d12_batch *batch,
struct d3d12_resource *res,
bool write)
{
uint8_t*state = d3d12_batch_acquire_reference(batch, res->bo);
uint8_t new_data = write ? batch_bo_reference_written : batch_bo_reference_read;
uint8_t old_data = (uint8_t)*state;
*state = (old_data | new_data);
}
void
d3d12_batch_reference_sampler_view(struct d3d12_batch *batch,
struct d3d12_sampler_view *sv)
{
struct set_entry *entry = _mesa_set_search(batch->sampler_views, sv);
if (!entry) {
entry = _mesa_set_add(batch->sampler_views, sv);
pipe_reference(NULL, &sv->base.reference);
d3d12_batch_reference_resource(batch, d3d12_resource(sv->base.texture), false);
}
}
void
d3d12_batch_reference_surface_texture(struct d3d12_batch *batch,
struct d3d12_surface *surf)
{
d3d12_batch_reference_resource(batch, d3d12_resource(surf->base.texture), true);
}
void
d3d12_batch_reference_object(struct d3d12_batch *batch,
ID3D12Object *object)
{
struct set_entry *entry = _mesa_set_search(batch->objects, object);
if (!entry) {
entry = _mesa_set_add(batch->objects, object);
object->AddRef();
}
}
void
d3d12_batch_reference_query(struct d3d12_batch *batch,
struct d3d12_query *query)
{
struct set_entry *entry = _mesa_set_search(batch->queries, query);
if (!entry) {
entry = _mesa_set_add(batch->queries, query);
pipe_reference(NULL, &query->reference);
}
}
+113
View File
@@ -0,0 +1,113 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_BATCH_H
#define D3D12_BATCH_H
#include "util/u_dynarray.h"
#include "util/hash_table.h"
#include "pipe/p_state.h"
#include <stdint.h>
#include "d3d12_common.h"
struct d3d12_bo;
struct d3d12_descriptor_heap;
struct d3d12_fence;
struct d3d12_sampler_desc_table_key
{
D3D12_CPU_DESCRIPTOR_HANDLE descs[PIPE_MAX_SHADER_SAMPLER_VIEWS];
unsigned count;
};
struct d3d12_batch {
struct d3d12_fence *fence;
struct hash_table *bos;
struct util_dynarray local_bos;
struct util_dynarray local_bo_pending;
struct util_dynarray bos_pending;
struct hash_table *sampler_tables;
struct set *sampler_views;
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
struct set *surfaces;
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
struct set *objects;
struct set *queries;
struct util_dynarray zombie_samplers;
ID3D12CommandAllocator *cmdalloc;
struct d3d12_descriptor_heap *sampler_heap;
struct d3d12_descriptor_heap *view_heap;
bool has_errors;
bool pending_memory_barrier;
uint64_t submit_id;
uint32_t ctx_id, ctx_index;
};
bool
d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
void
d3d12_destroy_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
void
d3d12_start_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
void
d3d12_end_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
bool
d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t timeout_ns);
bool
d3d12_batch_has_references(struct d3d12_batch *batch,
struct d3d12_bo *bo,
bool want_to_write);
void
d3d12_batch_reference_resource(struct d3d12_batch *batch,
struct d3d12_resource *res,
bool write);
void
d3d12_batch_reference_sampler_view(struct d3d12_batch *batch,
struct d3d12_sampler_view *sv);
void
d3d12_batch_reference_surface_texture(struct d3d12_batch *batch,
struct d3d12_surface *surf);
void
d3d12_batch_reference_object(struct d3d12_batch *batch,
ID3D12Object *object);
void
d3d12_batch_reference_query(struct d3d12_batch *batch,
struct d3d12_query *query);
#endif
+702
View File
@@ -0,0 +1,702 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_context.h"
#include "d3d12_compiler.h"
#include "d3d12_debug.h"
#include "d3d12_blit.h"
#include "d3d12_format.h"
#include "d3d12_query.h"
#include "d3d12_resource.h"
#include "d3d12_screen.h"
#include "util/u_blitter.h"
#include "util/format/u_format.h"
#include "nir_to_dxil.h"
#include "nir_builder.h"
static bool
is_resolve(const struct pipe_blit_info *info)
{
return info->src.resource->nr_samples > 1 &&
info->dst.resource->nr_samples <= 1;
}
static bool
resolve_supported(const struct pipe_blit_info *info)
{
assert(is_resolve(info));
// check for unsupported operations
if (util_format_is_depth_or_stencil(info->src.format) &&
info->mask != PIPE_MASK_Z) {
return false;
} else {
if (util_format_get_mask(info->dst.format) != info->mask ||
util_format_get_mask(info->src.format) != info->mask ||
util_format_has_alpha1(info->src.format))
return false;
}
if (info->filter != PIPE_TEX_FILTER_NEAREST ||
info->scissor_enable ||
info->swizzle_enable ||
info->num_window_rectangles > 0 ||
info->alpha_blend)
return false;
// formats need to match
struct d3d12_resource *src = d3d12_resource(info->src.resource);
struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
if (src->dxgi_format != dst->dxgi_format)
return false;
if (util_format_is_pure_integer(src->base.b.format))
return false;
// sizes needs to match
if (info->src.box.width != info->dst.box.width ||
info->src.box.height != info->dst.box.height)
return false;
// can only resolve full subresource
if (info->src.box.width != (int)u_minify(info->src.resource->width0,
info->src.level) ||
info->src.box.height != (int)u_minify(info->src.resource->height0,
info->src.level) ||
info->dst.box.width != (int)u_minify(info->dst.resource->width0,
info->dst.level) ||
info->dst.box.height != (int)u_minify(info->dst.resource->height0,
info->dst.level))
return false;
return true;
}
static void
blit_resolve(struct d3d12_context *ctx, const struct pipe_blit_info *info)
{
struct d3d12_batch *batch = d3d12_current_batch(ctx);
struct d3d12_resource *src = d3d12_resource(info->src.resource);
struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
d3d12_transition_resource_state(ctx, src,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_transition_resource_state(ctx, dst,
D3D12_RESOURCE_STATE_RESOLVE_DEST,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_apply_resource_states(ctx, false);
d3d12_batch_reference_resource(batch, src, false);
d3d12_batch_reference_resource(batch, dst, true);
DXGI_FORMAT dxgi_format = d3d12_get_resource_srv_format(src->base.b.format, src->base.b.target);
assert(src->dxgi_format == dst->dxgi_format);
ctx->cmdlist->ResolveSubresource(
d3d12_resource_resource(dst), info->dst.level,
d3d12_resource_resource(src), info->src.level,
dxgi_format);
ctx->has_commands = true;
}
static bool
formats_are_copy_compatible(enum pipe_format src, enum pipe_format dst)
{
if (src == dst)
return true;
/* We can skip the stencil copy */
if (util_format_get_depth_only(src) == dst ||
util_format_get_depth_only(dst) == src)
return true;
return false;
}
static bool
box_fits(const struct pipe_box *box, const struct pipe_resource *res, int level)
{
unsigned lwidth = u_minify(res->width0, level);
unsigned lheight= u_minify(res->height0, level);
unsigned ldepth = res->target == PIPE_TEXTURE_3D ? u_minify(res->depth0, level) :
res->array_size;
unsigned wb = box->x;
unsigned we = box->x + box->width;
unsigned hb = box->y;
unsigned he = box->y + box->height;
unsigned db = box->z;
unsigned de = box->z + box->depth;
return (wb <= lwidth && we <= lwidth &&
hb <= lheight && he <= lheight &&
db <= ldepth && de <= ldepth);
}
static bool
direct_copy_supported(struct d3d12_screen *screen,
const struct pipe_blit_info *info,
bool have_predication)
{
if (info->scissor_enable || info->alpha_blend || info->swizzle_enable ||
(have_predication && info->render_condition_enable) ||
MAX2(info->src.resource->nr_samples, 1) != MAX2(info->dst.resource->nr_samples, 1)) {
return false;
}
if (!formats_are_copy_compatible(info->src.format, info->dst.format))
return false;
if (info->src.format != info->src.resource->format ||
info->dst.format != info->dst.resource->format)
return false;
if (util_format_is_depth_or_stencil(info->src.format) && !(info->mask & PIPE_MASK_ZS)) {
return false;
}
if (!util_format_is_depth_or_stencil(info->src.format)) {
if (util_format_get_mask(info->dst.format) != info->mask ||
util_format_get_mask(info->src.format) != info->mask)
return false;
}
if (abs(info->src.box.height) != info->dst.box.height) {
return false;
}
if (info->src.box.height != info->dst.box.height &&
(!util_format_is_depth_or_stencil(info->src.format) ||
screen->opts2.ProgrammableSamplePositionsTier ==
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)) {
return false;
}
if (!box_fits(&info->dst.box, info->dst.resource, info->dst.level)) {
return false;
}
if (!box_fits(&info->src.box, info->src.resource, info->src.level)) {
return false;
}
if (info->src.box.width != info->dst.box.width) {
return false;
}
if (info->src.box.depth != info->dst.box.depth) {
return false;
}
if ((screen->opts2.ProgrammableSamplePositionsTier ==
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED &&
(info->src.resource->bind & PIPE_BIND_DEPTH_STENCIL ||
info->dst.resource->bind & PIPE_BIND_DEPTH_STENCIL)) ||
info->src.resource->nr_samples != info->dst.resource->nr_samples) {
if (info->dst.box.x != 0 ||
info->dst.box.y != 0 ||
info->dst.box.z != 0)
return false;
if (info->src.box.x != 0 ||
info->src.box.y != 0 ||
info->src.box.z != 0 ||
info->src.box.width != (int)u_minify(info->src.resource->width0,
info->src.level) ||
info->src.box.height != (int)u_minify(info->src.resource->height0,
info->src.level) ||
info->src.box.depth != (int)u_minify(info->src.resource->depth0,
info->src.level))
return false;
}
return true;
}
static bool
is_same_resource(const struct pipe_blit_info *info)
{
return d3d12_resource_resource(d3d12_resource(info->src.resource)) ==
d3d12_resource_resource(d3d12_resource(info->dst.resource)) &&
info->src.level == info->dst.level;
}
static void
blit_same_resource(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
struct pipe_blit_info dst_info = *info;
dst_info.src.level = 0;
dst_info.src.resource = create_staging_resource(ctx, d3d12_resource(info->src.resource),
info->src.level,
&info->src.box,
&dst_info.src.box, PIPE_MASK_RGBAZS);
ctx->base.blit(&ctx->base, &dst_info);
pipe_resource_reference(&dst_info.src.resource, NULL);
}
static void
util_blit_save_state(struct d3d12_context *ctx)
{
util_blitter_save_blend(ctx->blitter, ctx->gfx_pipeline_state.blend);
util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->gfx_pipeline_state.zsa);
util_blitter_save_vertex_elements(ctx->blitter, ctx->gfx_pipeline_state.ves);
util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
util_blitter_save_rasterizer(ctx->blitter, ctx->gfx_pipeline_state.rast);
util_blitter_save_fragment_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_FRAGMENT]);
util_blitter_save_vertex_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_VERTEX]);
util_blitter_save_geometry_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_GEOMETRY]);
util_blitter_save_tessctrl_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_TESS_CTRL]);
util_blitter_save_tesseval_shader(ctx->blitter, ctx->gfx_stages[MESA_SHADER_TESS_EVAL]);
util_blitter_save_framebuffer(ctx->blitter, &ctx->fb);
util_blitter_save_viewport(ctx->blitter, ctx->viewport_states);
util_blitter_save_scissor(ctx->blitter, ctx->scissor_states);
util_blitter_save_fragment_sampler_states(ctx->blitter,
ctx->num_samplers[MESA_SHADER_FRAGMENT],
(void **)ctx->samplers[MESA_SHADER_FRAGMENT]);
util_blitter_save_fragment_sampler_views(ctx->blitter,
ctx->num_sampler_views[MESA_SHADER_FRAGMENT],
ctx->sampler_views[MESA_SHADER_FRAGMENT]);
util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->cbufs[MESA_SHADER_FRAGMENT]);
util_blitter_save_vertex_buffers(ctx->blitter, ctx->vbs, ctx->num_vbs);
util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask, 0);
util_blitter_save_so_targets(ctx->blitter, ctx->gfx_pipeline_state.num_so_targets, ctx->so_targets,
MESA_PRIM_UNKNOWN);
}
static void
util_blit(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
util_blit_save_state(ctx);
util_blitter_blit(ctx->blitter, info, NULL);
}
static bool
resolve_stencil_supported(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
assert(is_resolve(info));
if (!util_format_is_depth_or_stencil(info->src.format) ||
!(info->mask & PIPE_MASK_S))
return false;
if (info->mask & PIPE_MASK_Z) {
struct pipe_blit_info new_info = *info;
new_info.mask = PIPE_MASK_Z;
if (!resolve_supported(&new_info) &&
!util_blitter_is_blit_supported(ctx->blitter, &new_info))
return false;
}
struct pipe_blit_info new_info = *info;
new_info.dst.format = PIPE_FORMAT_R8_UINT;
return util_blitter_is_blit_supported(ctx->blitter, &new_info);
}
static struct pipe_resource *
create_tmp_resource(struct pipe_screen *screen,
const struct pipe_blit_info *info)
{
struct pipe_resource tpl = {};
tpl.width0 = info->dst.box.width;
tpl.height0 = static_cast<uint16_t>(info->dst.box.height);
tpl.depth0 = info->dst.box.depth;
tpl.array_size = 1;
tpl.format = PIPE_FORMAT_R8_UINT;
tpl.target = info->dst.resource->target;
tpl.nr_samples = info->dst.resource->nr_samples;
tpl.nr_storage_samples = info->dst.resource->nr_storage_samples;
tpl.usage = PIPE_USAGE_STREAM;
tpl.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
return screen->resource_create(screen, &tpl);
}
static void *
get_stencil_resolve_vs(struct d3d12_context *ctx)
{
if (ctx->stencil_resolve_vs)
return ctx->stencil_resolve_vs;
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX,
&d3d12_screen(ctx->base.screen)->nir_options,
"linear_blit_vs");
const struct glsl_type *vec4 = glsl_vec4_type();
nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
vec4, "pos");
nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,
vec4, "gl_Position");
pos_out->data.location = VARYING_SLOT_POS;
nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf);
struct pipe_shader_state state = {};
state.type = PIPE_SHADER_IR_NIR;
state.ir.nir = b.shader;
ctx->stencil_resolve_vs = ctx->base.create_vs_state(&ctx->base, &state);
return ctx->stencil_resolve_vs;
}
static void *
get_stencil_resolve_fs(struct d3d12_context *ctx, bool no_flip)
{
if (!no_flip && ctx->stencil_resolve_fs)
return ctx->stencil_resolve_fs;
if (no_flip && ctx->stencil_resolve_fs_no_flip)
return ctx->stencil_resolve_fs_no_flip;
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
&d3d12_screen(ctx->base.screen)->nir_options,
no_flip ? "stencil_resolve_fs_no_flip" : "stencil_resolve_fs");
nir_variable *stencil_out = nir_variable_create(b.shader,
nir_var_shader_out,
glsl_uint_type(),
"stencil_out");
stencil_out->data.location = FRAG_RESULT_COLOR;
const struct glsl_type *sampler_type =
glsl_sampler_type(GLSL_SAMPLER_DIM_MS, false, false, GLSL_TYPE_UINT);
nir_variable *sampler = nir_variable_create(b.shader, nir_var_uniform,
sampler_type, "stencil_tex");
sampler->data.binding = 0;
sampler->data.explicit_binding = true;
nir_def *tex_deref = &nir_build_deref_var(&b, sampler)->def;
nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
glsl_vec4_type(), "pos");
pos_in->data.location = VARYING_SLOT_POS; // VARYING_SLOT_VAR0?
nir_def *pos = nir_load_var(&b, pos_in);
nir_def *pos_src;
if (no_flip)
pos_src = pos;
else {
nir_tex_instr *txs = nir_tex_instr_create(b.shader, 1);
txs->op = nir_texop_txs;
txs->sampler_dim = GLSL_SAMPLER_DIM_MS;
txs->src[0] = nir_tex_src_for_ssa(nir_tex_src_texture_deref, tex_deref);
txs->is_array = false;
txs->dest_type = nir_type_int;
nir_def_init(&txs->instr, &txs->def, 2, 32);
nir_builder_instr_insert(&b, &txs->instr);
pos_src = nir_vec4(&b,
nir_channel(&b, pos, 0),
/*Height - pos_dest.y - 1*/
nir_fsub(&b,
nir_fsub(&b,
nir_channel(&b, nir_i2f32(&b, &txs->def), 1),
nir_channel(&b, pos, 1)),
nir_imm_float(&b, 1.0)),
nir_channel(&b, pos, 2),
nir_channel(&b, pos, 3));
}
nir_tex_instr *tex = nir_tex_instr_create(b.shader, 3);
tex->sampler_dim = GLSL_SAMPLER_DIM_MS;
tex->op = nir_texop_txf_ms;
tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord,
nir_trim_vector(&b, nir_f2i32(&b, pos_src), 2));
tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_ms_index, nir_imm_int(&b, 0)); /* just use first sample */
tex->src[2] = nir_tex_src_for_ssa(nir_tex_src_texture_deref, tex_deref);
tex->dest_type = nir_type_uint32;
tex->is_array = false;
tex->coord_components = 2;
nir_def_init(&tex->instr, &tex->def, 4, 32);
nir_builder_instr_insert(&b, &tex->instr);
nir_store_var(&b, stencil_out, nir_channel(&b, &tex->def, 1), 0x1);
struct pipe_shader_state state = {};
state.type = PIPE_SHADER_IR_NIR;
state.ir.nir = b.shader;
void *result;
if (no_flip) {
result = ctx->base.create_fs_state(&ctx->base, &state);
ctx->stencil_resolve_fs_no_flip = result;
} else {
result = ctx->base.create_fs_state(&ctx->base, &state);
ctx->stencil_resolve_fs = result;
}
return result;
}
static void *
get_sampler_state(struct d3d12_context *ctx)
{
if (ctx->sampler_state)
return ctx->sampler_state;
struct pipe_sampler_state state;
memset(&state, 0, sizeof(state));
state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
return ctx->sampler_state = ctx->base.create_sampler_state(&ctx->base, &state);
}
static struct pipe_resource *
resolve_stencil_to_temp(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
struct pipe_context *pctx = &ctx->base;
struct pipe_resource *tmp = create_tmp_resource(pctx->screen, info);
if (!tmp) {
debug_printf("D3D12: failed to create stencil-resolve temp-resource\n");
return NULL;
}
assert(tmp->nr_samples < 2);
/* resolve stencil into tmp */
struct pipe_surface dst_tmpl;
util_blitter_default_dst_texture(&dst_tmpl, tmp, 0, 0);
dst_tmpl.format = tmp->format;
struct pipe_sampler_view src_templ, *src_view;
util_blitter_default_src_texture(ctx->blitter, &src_templ,
info->src.resource, info->src.level);
src_templ.format = util_format_stencil_only(info->src.format);
src_view = pctx->create_sampler_view(pctx, info->src.resource, &src_templ);
void *sampler_state = get_sampler_state(ctx);
util_blit_save_state(ctx);
pctx->set_sampler_views(pctx, MESA_SHADER_FRAGMENT, 0, 1, 0, &src_view);
pctx->bind_sampler_states(pctx, MESA_SHADER_FRAGMENT, 0, 1, &sampler_state);
util_blitter_custom_shader(ctx->blitter, &dst_tmpl,
(uint16_t)pipe_surface_width(&dst_tmpl),
(uint16_t)pipe_surface_height(&dst_tmpl),
get_stencil_resolve_vs(ctx),
get_stencil_resolve_fs(ctx, info->src.box.height == info->dst.box.height));
util_blitter_restore_textures(ctx->blitter);
pipe_sampler_view_reference(&src_view, NULL);
return tmp;
}
static void
blit_resolve_stencil(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
assert(info->mask & PIPE_MASK_S);
if (D3D12_DEBUG_BLIT & d3d12_debug)
debug_printf("D3D12 BLIT: blit_resolve_stencil\n");
if (info->mask & PIPE_MASK_Z) {
/* resolve depth into dst */
struct pipe_blit_info new_info = *info;
new_info.mask = PIPE_MASK_Z;
if (resolve_supported(&new_info))
blit_resolve(ctx, &new_info);
else
util_blit(ctx, &new_info);
}
struct pipe_resource *tmp = resolve_stencil_to_temp(ctx, info);
/* copy resolved stencil into dst */
struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
d3d12_transition_subresources_state(ctx, d3d12_resource(tmp),
0, 1, 0, 1, 0, 1,
D3D12_RESOURCE_STATE_COPY_SOURCE,
D3D12_TRANSITION_FLAG_NONE);
d3d12_transition_subresources_state(ctx, dst,
0, 1, 0, 1, 1, 1,
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_apply_resource_states(ctx, false);
struct d3d12_batch *batch = d3d12_current_batch(ctx);
d3d12_batch_reference_resource(batch, d3d12_resource(tmp), false);
d3d12_batch_reference_resource(batch, dst, true);
D3D12_BOX src_box;
src_box.left = src_box.top = src_box.front = 0;
src_box.right = tmp->width0;
src_box.bottom = tmp->height0;
src_box.back = tmp->depth0;
D3D12_TEXTURE_COPY_LOCATION src_loc;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src_loc.SubresourceIndex = 0;
src_loc.pResource = d3d12_resource_resource(d3d12_resource(tmp));
D3D12_TEXTURE_COPY_LOCATION dst_loc;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 1;
dst_loc.pResource = d3d12_resource_resource(dst);
ctx->cmdlist->CopyTextureRegion(&dst_loc, info->dst.box.x,
info->dst.box.y, info->dst.box.z,
&src_loc, &src_box);
ctx->has_commands = true;
pipe_resource_reference(&tmp, NULL);
}
static bool
replicate_stencil_supported(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
if (!util_format_is_depth_or_stencil(info->src.format) ||
!(info->mask & PIPE_MASK_S))
return false;
if (info->mask & PIPE_MASK_Z) {
struct pipe_blit_info new_info = *info;
new_info.mask = PIPE_MASK_Z;
if (!util_blitter_is_blit_supported(ctx->blitter, &new_info))
return false;
}
return true;
}
static void
blit_replicate_stencil(struct d3d12_context *ctx,
const struct pipe_blit_info *info)
{
assert(info->mask & PIPE_MASK_S);
if (D3D12_DEBUG_BLIT & d3d12_debug)
debug_printf("D3D12 BLIT: blit_replicate_stencil\n");
if (info->mask & PIPE_MASK_Z) {
/* resolve depth into dst */
struct pipe_blit_info new_info = *info;
new_info.mask = PIPE_MASK_Z;
util_blit(ctx, &new_info);
}
struct pipe_surface dst_templ;
util_blitter_default_dst_texture(&dst_templ, info->dst.resource,
info->dst.level, info->dst.box.z);
util_blit_save_state(ctx);
util_blitter_clear_depth_stencil(ctx->blitter, &dst_templ, PIPE_CLEAR_STENCIL,
0, 0, info->dst.box.x, info->dst.box.y,
info->dst.box.width, info->dst.box.height);
util_blit_save_state(ctx);
util_blitter_stencil_fallback(ctx->blitter, info->dst.resource,
info->dst.level,
&info->dst.box,
info->src.resource,
info->src.level,
&info->src.box,
info->scissor_enable ? &info->scissor : NULL);
}
void
d3d12_blit(struct pipe_context *pctx,
const struct pipe_blit_info *info)
{
struct d3d12_context *ctx = d3d12_context(pctx);
if (!info->render_condition_enable && ctx->current_predication) {
if (D3D12_DEBUG_BLIT & d3d12_debug)
debug_printf("D3D12 BLIT: Disable predication\n");
ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
}
if (D3D12_DEBUG_BLIT & d3d12_debug) {
debug_printf("D3D12 BLIT: from %s@%d msaa:%d %dx%dx%d + %dx%dx%d\n",
util_format_name(info->src.format), info->src.level,
info->src.resource->nr_samples,
info->src.box.x, info->src.box.y, info->src.box.z,
info->src.box.width, info->src.box.height, info->src.box.depth);
debug_printf(" to %s@%d msaa:%d %dx%dx%d + %dx%dx%d ",
util_format_name(info->dst.format), info->dst.level,
info->dst.resource->nr_samples,
info->dst.box.x, info->dst.box.y, info->dst.box.z,
info->dst.box.width, info->dst.box.height, info->dst.box.depth);
debug_printf("| flags %s%s%s\n",
info->render_condition_enable ? "cond " : "",
info->scissor_enable ? "scissor " : "",
info->alpha_blend ? "blend" : "");
}
if (is_same_resource(info))
blit_same_resource(ctx, info);
else if (is_resolve(info)) {
if (resolve_supported(info))
blit_resolve(ctx, info);
else if (util_blitter_is_blit_supported(ctx->blitter, info))
util_blit(ctx, info);
else if (resolve_stencil_supported(ctx, info))
blit_resolve_stencil(ctx, info);
else
debug_printf("D3D12: resolve unsupported %s -> %s\n",
util_format_short_name(info->src.resource->format),
util_format_short_name(info->dst.resource->format));
} else if (direct_copy_supported(d3d12_screen(pctx->screen), info,
ctx->current_predication != nullptr))
d3d12_direct_copy(ctx, d3d12_resource(info->dst.resource),
info->dst.level, &info->dst.box,
d3d12_resource(info->src.resource),
info->src.level, &info->src.box, info->mask);
else if (util_blitter_is_blit_supported(ctx->blitter, info))
util_blit(ctx, info);
else if (replicate_stencil_supported(ctx, info))
blit_replicate_stencil(ctx, info);
else
debug_printf("D3D12: blit unsupported %s -> %s\n",
util_format_short_name(info->src.resource->format),
util_format_short_name(info->dst.resource->format));
if (d3d12_screen(pctx->screen)->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
if (!info->render_condition_enable && ctx->current_predication) {
d3d12_enable_predication(ctx);
if (D3D12_DEBUG_BLIT & d3d12_debug)
debug_printf("D3D12 BLIT: Re-enable predication\n");
}
}
}
void
d3d12_context_blit_init(struct pipe_context *ctx)
{
ctx->blit = d3d12_blit;
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_BLIT_H
#define D3D12_BLIT_H
struct d3d12_context;
struct d3d12_resource;
struct pipe_box;
void
d3d12_context_blit_init(struct pipe_context *ctx);
void
d3d12_context_copy_init(struct pipe_context *ctx);
void
d3d12_direct_copy(struct d3d12_context *ctx,
struct d3d12_resource *dst,
unsigned dst_level,
const struct pipe_box *pdst_box,
struct d3d12_resource *src,
unsigned src_level,
const struct pipe_box *psrc_box, unsigned mask);
struct pipe_resource *
create_staging_resource(struct d3d12_context *ctx,
struct d3d12_resource *src,
unsigned src_level,
const struct pipe_box *src_box,
struct pipe_box *dst_box,
unsigned mask);
#endif // D3D12_BLIT_H
+472
View File
@@ -0,0 +1,472 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_bufmgr.h"
#include "d3d12_context.h"
#include "d3d12_fence.h"
#include "d3d12_format.h"
#include "d3d12_screen.h"
#include "pipebuffer/pb_buffer.h"
#include "pipebuffer/pb_bufmgr.h"
#include "util/format/u_format.h"
#include "util/set.h"
#include "util/u_memory.h"
#include <dxguids/dxguids.h>
struct d3d12_bufmgr {
struct pb_manager base;
struct d3d12_screen *screen;
};
extern const struct pb_vtbl d3d12_buffer_vtbl;
static inline struct d3d12_bufmgr *
d3d12_bufmgr(struct pb_manager *mgr)
{
assert(mgr);
return (struct d3d12_bufmgr *)mgr;
}
static void
describe_direct_bo(char *buf, struct d3d12_bo *ptr)
{
sprintf(buf, "d3d12_bo<direct,%p,0x%x>", ptr->res, (unsigned)ptr->estimated_size);
}
static void
describe_suballoc_bo(char *buf, struct d3d12_bo *ptr)
{
char res[128];
uint64_t offset;
d3d12_bo *base = d3d12_bo_get_base(ptr, &offset);
describe_direct_bo(res, base);
sprintf(buf, "d3d12_bo<suballoc<%s>,0x%x,0x%x>", res,
(unsigned)ptr->buffer->base.size, (unsigned)offset);
}
void
d3d12_debug_describe_bo(char *buf, struct d3d12_bo *ptr)
{
if (ptr->buffer)
describe_suballoc_bo(buf, ptr);
else
describe_direct_bo(buf, ptr);
}
struct d3d12_bo *
d3d12_bo_wrap_res(struct d3d12_screen *screen, ID3D12Resource *res, enum d3d12_residency_status residency)
{
struct d3d12_bo *bo;
bo = MALLOC_STRUCT(d3d12_bo);
if (!bo)
return NULL;
memset(bo, 0, offsetof(d3d12_bo, local_context_states));
D3D12_RESOURCE_DESC desc = GetDesc(res);
unsigned array_size = desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : desc.DepthOrArraySize;
unsigned total_subresources = desc.MipLevels * array_size * d3d12_non_opaque_plane_count(desc.Format);
bool supports_simultaneous_access = d3d12_resource_supports_simultaneous_access(&desc);
pipe_reference_init(&bo->reference, 1);
bo->screen = screen;
bo->res = res;
bo->unique_id = p_atomic_inc_return(&screen->resource_id_generator);
if (!supports_simultaneous_access)
d3d12_resource_state_init(&bo->global_state, total_subresources, false);
bo->residency_status = residency;
bo->last_used_timestamp = 0;
desc.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
bo->estimated_size = GetResourceAllocationInfo(screen->dev, 0, 1, &desc).SizeInBytes;
if (residency == d3d12_resident) {
mtx_lock(&screen->submit_mutex);
list_add(&bo->residency_list_entry, &screen->residency_list);
mtx_unlock(&screen->submit_mutex);
}
return bo;
}
struct d3d12_bo *
d3d12_bo_new(struct d3d12_screen *screen, uint64_t size, const pb_desc *pb_desc)
{
ID3D12Device *dev = screen->dev;
ID3D12Resource *res;
D3D12_RESOURCE_DESC res_desc;
res_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
res_desc.Format = DXGI_FORMAT_UNKNOWN;
res_desc.Alignment = 0;
res_desc.Width = size;
res_desc.Height = 1;
res_desc.DepthOrArraySize = 1;
res_desc.MipLevels = 1;
res_desc.SampleDesc.Count = 1;
res_desc.SampleDesc.Quality = 0;
res_desc.Flags = (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;
res_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_DEFAULT;
if (pb_desc->usage & PB_USAGE_CPU_READ)
heap_type = D3D12_HEAP_TYPE_READBACK;
else if (pb_desc->usage & PB_USAGE_CPU_WRITE)
heap_type = D3D12_HEAP_TYPE_UPLOAD;
D3D12_HEAP_FLAGS heap_flags = screen->support_create_not_resident ?
D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT : D3D12_HEAP_FLAG_NONE;
enum d3d12_residency_status init_residency = screen->support_create_not_resident ?
d3d12_evicted : d3d12_resident;
D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(dev, heap_type);
d3d12_screen_reclaim_completed(screen);
HRESULT hres;
do {
hres = dev->CreateCommittedResource(&heap_pris,
heap_flags,
&res_desc,
D3D12_RESOURCE_STATE_COMMON,
NULL,
IID_PPV_ARGS(&res));
} while (hres == E_OUTOFMEMORY && d3d12_screen_reclaim_one(screen));
if (FAILED(hres))
return NULL;
return d3d12_bo_wrap_res(screen, res, init_residency);
}
struct d3d12_bo *
d3d12_bo_wrap_buffer(struct d3d12_screen *screen, struct pb_buffer *buf)
{
struct d3d12_bo *bo;
bo = MALLOC_STRUCT(d3d12_bo);
if (!bo)
return NULL;
memset(bo, 0, offsetof(d3d12_bo, local_context_states));
pipe_reference_init(&bo->reference, 1);
bo->screen = screen;
bo->buffer = buf;
bo->unique_id = p_atomic_inc_return(&screen->resource_id_generator);
bo->residency_status = d3d12_evicted;
return bo;
}
void
d3d12_bo_unreference(struct d3d12_bo *bo)
{
if (bo == NULL)
return;
assert(pipe_is_referenced(&bo->reference));
if (pipe_reference_described(&bo->reference, NULL,
(debug_reference_descriptor)
d3d12_debug_describe_bo)) {
if (bo->buffer)
pb_reference(&bo->buffer, NULL);
mtx_lock(&bo->screen->submit_mutex);
if (bo->residency_status == d3d12_resident)
list_del(&bo->residency_list_entry);
/* MSVC's offsetof fails when the name is ambiguous between struct and function */
typedef struct d3d12_context d3d12_context_type;
list_for_each_entry(d3d12_context_type, ctx, &bo->screen->context_list, context_list_entry) {
if (ctx->id == D3D12_CONTEXT_NO_ID) {
util_dynarray_append_typed(&ctx->recently_destroyed_bos, uint64_t, bo->unique_id);
} else if (bo->local_context_state_mask & (1u << ctx->id)) {
_mesa_set_remove_key(ctx->local_state_bos, bo);
}
}
mtx_unlock(&bo->screen->submit_mutex);
d3d12_resource_state_cleanup(&bo->global_state);
if (bo->res)
bo->res->Release();
uint64_t mask = bo->local_context_state_mask;
while (mask) {
int ctxid = u_bit_scan64(&mask);
d3d12_destroy_context_state_table_entry(&bo->local_context_states[ctxid]);
}
FREE(bo);
}
}
bool
d3d12_screen_reclaim_completed(struct d3d12_screen *screen)
{
uint64_t completed = screen->fence->GetCompletedValue();
struct list_head retired;
list_inithead(&retired);
mtx_lock(&screen->pending_free_lock);
list_for_each_entry_safe(struct d3d12_pending_free_entry, entry,
&screen->pending_free_list, link) {
if (entry->fence_value > completed)
break;
list_del(&entry->link);
list_addtail(&entry->link, &retired);
}
mtx_unlock(&screen->pending_free_lock);
bool dropped = !list_is_empty(&retired);
list_for_each_entry_safe(struct d3d12_pending_free_entry, entry, &retired, link) {
d3d12_bo_unreference(entry->bo);
FREE(entry);
}
return dropped;
}
bool
d3d12_screen_reclaim_one(struct d3d12_screen *screen)
{
uint64_t target = 0;
bool have_target = false;
mtx_lock(&screen->pending_free_lock);
if (!list_is_empty(&screen->pending_free_list)) {
struct d3d12_pending_free_entry *head =
list_first_entry(&screen->pending_free_list,
struct d3d12_pending_free_entry, link);
target = head->fence_value;
have_target = true;
}
mtx_unlock(&screen->pending_free_lock);
if (!have_target)
return false;
if (screen->fence->GetCompletedValue() < target)
screen->fence->SetEventOnCompletion(target, nullptr);
d3d12_screen_reclaim_completed(screen);
return true;
}
void *
d3d12_bo_map(struct d3d12_bo *bo, D3D12_RANGE *range)
{
struct d3d12_bo *base_bo;
D3D12_RANGE offset_range = {0, 0};
uint64_t offset;
void *ptr;
base_bo = d3d12_bo_get_base(bo, &offset);
if (!range || range->Begin >= range->End) {
offset_range.Begin = static_cast<size_t>(offset);
offset_range.End = static_cast<size_t>(offset + d3d12_bo_get_size(bo));
range = &offset_range;
} else {
offset_range.Begin = static_cast<size_t>(range->Begin + offset);
offset_range.End = static_cast<size_t>(range->End + offset);
range = &offset_range;
}
if (FAILED(base_bo->res->Map(0, range, &ptr)))
return NULL;
return (uint8_t *)ptr + (range ? range->Begin : 0);
}
void
d3d12_bo_unmap(struct d3d12_bo *bo, D3D12_RANGE *range)
{
struct d3d12_bo *base_bo;
D3D12_RANGE offset_range = {0, 0};
uint64_t offset;
base_bo = d3d12_bo_get_base(bo, &offset);
if (!range || range->Begin >= range->End) {
offset_range.Begin = static_cast<size_t>(offset);
offset_range.End = static_cast<size_t>(offset + d3d12_bo_get_size(bo));
range = &offset_range;
} else {
offset_range.Begin = static_cast<size_t>(range->Begin + offset);
offset_range.End = static_cast<size_t>(range->End + offset);
range = &offset_range;
}
base_bo->res->Unmap(0, range);
}
static void
d3d12_buffer_destroy(void *winsys, struct pb_buffer *pbuf)
{
struct d3d12_buffer *buf = d3d12_buffer(pbuf);
if (buf->map)
d3d12_bo_unmap(buf->bo, &buf->range);
d3d12_bo_unreference(buf->bo);
FREE(buf);
}
static void *
d3d12_buffer_map(struct pb_buffer *pbuf,
enum pb_usage_flags flags,
void *flush_ctx)
{
return d3d12_buffer(pbuf)->map;
}
static void
d3d12_buffer_unmap(struct pb_buffer *pbuf)
{
}
static void
d3d12_buffer_get_base_buffer(struct pb_buffer *buf,
struct pb_buffer **base_buf,
pb_size *offset)
{
*base_buf = buf;
*offset = 0;
}
static enum pipe_error
d3d12_buffer_validate(struct pb_buffer *pbuf,
struct pb_validate *vl,
enum pb_usage_flags flags )
{
/* Always pinned */
return PIPE_OK;
}
static void
d3d12_buffer_fence(struct pb_buffer *pbuf,
struct pipe_fence_handle *fence)
{
if (!fence)
return;
struct d3d12_buffer *buf = d3d12_buffer(pbuf);
struct d3d12_fence *f = d3d12_fence(fence);
uint64_t offset;
struct d3d12_bo *base = d3d12_bo_get_base(buf->bo, &offset);
if (f->cmdqueue_fence != base->screen->fence)
return;
if (f->value > base->last_used_fence)
base->last_used_fence = f->value;
}
const struct pb_vtbl d3d12_buffer_vtbl = {
d3d12_buffer_destroy,
d3d12_buffer_map,
d3d12_buffer_unmap,
d3d12_buffer_validate,
d3d12_buffer_fence,
d3d12_buffer_get_base_buffer
};
static struct pb_buffer *
d3d12_bufmgr_create_buffer(struct pb_manager *pmgr,
pb_size size,
const struct pb_desc *pb_desc)
{
struct d3d12_bufmgr *mgr = d3d12_bufmgr(pmgr);
struct d3d12_buffer *buf;
buf = CALLOC_STRUCT(d3d12_buffer);
if (!buf)
return NULL;
pipe_reference_init(&buf->base.base.reference, 1);
buf->base.base.alignment_log2 = static_cast<uint8_t>(util_logbase2(pb_desc->alignment));
buf->base.base.usage = static_cast<uint16_t>(pb_desc->usage);
buf->base.vtbl = &d3d12_buffer_vtbl;
buf->base.base.size = size;
buf->range.Begin = 0;
buf->range.End = static_cast<size_t>(size);
buf->bo = d3d12_bo_new(mgr->screen, size, pb_desc);
if (!buf->bo) {
FREE(buf);
return NULL;
}
if (pb_desc->usage & PB_USAGE_CPU_READ_WRITE) {
buf->map = d3d12_bo_map(buf->bo, &buf->range);
if (!buf->map) {
d3d12_bo_unreference(buf->bo);
FREE(buf);
return NULL;
}
}
return &buf->base;
}
static void
d3d12_bufmgr_flush(struct pb_manager *mgr)
{
/* No-op */
}
static void
d3d12_bufmgr_destroy(struct pb_manager *_mgr)
{
struct d3d12_bufmgr *mgr = d3d12_bufmgr(_mgr);
FREE(mgr);
}
static bool
d3d12_bufmgr_is_buffer_busy(struct pb_manager *_mgr, struct pb_buffer *_buf)
{
struct d3d12_bufmgr *mgr = d3d12_bufmgr(_mgr);
struct d3d12_buffer *buf = d3d12_buffer(_buf);
uint64_t offset;
struct d3d12_bo *base = d3d12_bo_get_base(buf->bo, &offset);
return base->last_used_fence > mgr->screen->fence->GetCompletedValue();
}
struct pb_manager *
d3d12_bufmgr_create(struct d3d12_screen *screen)
{
struct d3d12_bufmgr *mgr;
mgr = CALLOC_STRUCT(d3d12_bufmgr);
if (!mgr)
return NULL;
mgr->base.destroy = d3d12_bufmgr_destroy;
mgr->base.create_buffer = d3d12_bufmgr_create_buffer;
mgr->base.flush = d3d12_bufmgr_flush;
mgr->base.is_buffer_busy = d3d12_bufmgr_is_buffer_busy;
mgr->screen = screen;
return &mgr->base;
}
+176
View File
@@ -0,0 +1,176 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_BUFMGR_H
#define D3D12_BUFMGR_H
#include "pipebuffer/pb_buffer.h"
#include "util/u_atomic.h"
#include "util/list.h"
#include "d3d12_common.h"
#include "d3d12_resource_state.h"
struct d3d12_bufmgr;
struct d3d12_screen;
struct pb_manager;
enum d3d12_residency_status {
d3d12_evicted,
d3d12_resident,
d3d12_permanently_resident,
};
enum batch_bo_reference_state : uint8_t {
batch_bo_reference_none = 0,
batch_bo_reference_read = (1 << 0),
batch_bo_reference_written = (1 << 1),
};
struct d3d12_bo {
struct pipe_reference reference;
struct d3d12_screen *screen;
ID3D12Resource *res;
struct pb_buffer *buffer;
struct d3d12_resource_state global_state;
/* Used as a key in per-context resource state maps,
* to avoid needing to lock them for single-threaded lookups to
* protect against resource destruction.
*/
uint64_t unique_id;
#ifndef NDEBUG
bool is_front_buffer;
#endif
struct list_head residency_list_entry;
uint64_t estimated_size;
int64_t last_used_timestamp;
uint64_t last_used_fence;
uint64_t last_used_periodic_notification_index;
enum d3d12_residency_status residency_status;
uint16_t local_needs_resolve_state;
unsigned local_context_state_mask;
uint8_t local_reference_mask[16];
d3d12_context_state_table_entry local_context_states[16];
uint8_t local_reference_state[16][8];
};
struct d3d12_buffer {
struct pb_buffer base;
struct d3d12_bo *bo;
D3D12_RANGE range;
void *map;
};
static inline struct d3d12_buffer *
d3d12_buffer(struct pb_buffer *buf)
{
assert(buf);
return (struct d3d12_buffer *)buf;
}
static inline struct d3d12_bo *
d3d12_bo_get_base(struct d3d12_bo *bo, uint64_t *offset)
{
if (bo->buffer) {
struct pb_buffer *base_buffer;
pb_get_base_buffer(bo->buffer, &base_buffer, offset);
return d3d12_buffer(base_buffer)->bo;
} else {
*offset = 0;
return bo;
}
}
static inline uint64_t
d3d12_bo_get_size(struct d3d12_bo *bo)
{
if (bo->buffer)
return bo->buffer->base.size;
else
return GetDesc(bo->res).Width;
}
static inline bool
d3d12_bo_is_suballocated(struct d3d12_bo *bo)
{
struct d3d12_bo *base_bo;
uint64_t offset;
if (!bo->buffer)
return false;
base_bo = d3d12_bo_get_base(bo, &offset);
return d3d12_bo_get_size(base_bo) != d3d12_bo_get_size(bo);
}
struct d3d12_bo *
d3d12_bo_new(struct d3d12_screen *screen, uint64_t size, uint64_t alignment);
struct d3d12_bo *
d3d12_bo_wrap_res(struct d3d12_screen *screen, ID3D12Resource *res, enum d3d12_residency_status residency);
struct d3d12_bo *
d3d12_bo_wrap_buffer(struct d3d12_screen *screen, struct pb_buffer *buf);
void
d3d12_debug_describe_bo(char* buf, struct d3d12_bo* ptr);
static inline void
d3d12_bo_reference(struct d3d12_bo *bo)
{
pipe_reference_described(NULL, &bo->reference,
(debug_reference_descriptor)
d3d12_debug_describe_bo);
}
void
d3d12_bo_unreference(struct d3d12_bo *bo);
void *
d3d12_bo_map(struct d3d12_bo *bo, D3D12_RANGE *range);
void
d3d12_bo_unmap(struct d3d12_bo *bo, D3D12_RANGE *range);
struct d3d12_pending_free_entry {
struct list_head link;
struct d3d12_bo *bo;
uint64_t fence_value;
};
bool
d3d12_screen_reclaim_completed(struct d3d12_screen *screen);
bool
d3d12_screen_reclaim_one(struct d3d12_screen *screen);
struct pb_manager *
d3d12_bufmgr_create(struct d3d12_screen *screen);
#endif
@@ -0,0 +1,122 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_cmd_signature.h"
#include "d3d12_compiler.h"
#include "d3d12_screen.h"
#include "util/u_memory.h"
#include <dxguids/dxguids.h>
struct d3d12_cmd_signature {
struct d3d12_cmd_signature_key key;
ID3D12CommandSignature *sig;
};
static ID3D12CommandSignature *
create_cmd_signature(struct d3d12_context *ctx, const struct d3d12_cmd_signature_key *key)
{
D3D12_COMMAND_SIGNATURE_DESC cmd_sig_desc = {};
D3D12_INDIRECT_ARGUMENT_DESC indirect_args[2] = {};
unsigned num_args = 0;
if (key->draw_or_dispatch_params) {
indirect_args[num_args].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
indirect_args[num_args].Constant.RootParameterIndex = key->params_root_const_param;
indirect_args[num_args].Constant.DestOffsetIn32BitValues = key->params_root_const_offset;
indirect_args[num_args++].Constant.Num32BitValuesToSet = key->compute ? 3 : 4;
}
indirect_args[num_args++].Type = key->compute ? D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH :
key->indexed ? D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED :
D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
cmd_sig_desc.ByteStride = key->multi_draw_stride;
cmd_sig_desc.NumArgumentDescs = num_args;
cmd_sig_desc.pArgumentDescs = indirect_args;
ID3D12CommandSignature *ret = nullptr;
d3d12_screen(ctx->base.screen)->dev->CreateCommandSignature(&cmd_sig_desc, key->root_sig,
IID_PPV_ARGS(&ret));
return ret;
}
ID3D12CommandSignature *
d3d12_get_cmd_signature(struct d3d12_context *ctx,
const struct d3d12_cmd_signature_key *key)
{
struct hash_entry *entry = _mesa_hash_table_search(ctx->cmd_signature_cache, &key);
if (!entry) {
struct d3d12_cmd_signature *data =
(struct d3d12_cmd_signature *)MALLOC(sizeof(struct d3d12_cmd_signature));
if (!data)
return NULL;
memcpy(&data->key, key, sizeof(*key));
data->sig = create_cmd_signature(ctx, key);
if (!data->sig) {
FREE(data);
return NULL;
}
entry = _mesa_hash_table_insert(ctx->cmd_signature_cache, &data->key, data);
assert(entry);
}
return ((struct d3d12_cmd_signature *)entry->data)->sig;
}
static uint32_t
hash_cmd_signature_key(const void *key)
{
return _mesa_hash_data(key, sizeof(struct d3d12_cmd_signature_key));
}
static bool
equals_cmd_signature_key(const void *a, const void *b)
{
return memcmp(a, b, sizeof(struct d3d12_cmd_signature_key)) == 0;
}
void
d3d12_cmd_signature_cache_init(struct d3d12_context *ctx)
{
ctx->cmd_signature_cache = _mesa_hash_table_create(NULL,
hash_cmd_signature_key,
equals_cmd_signature_key);
}
static void
delete_entry(struct hash_entry *entry)
{
struct d3d12_cmd_signature *data = (struct d3d12_cmd_signature *)entry->data;
data->sig->Release();
FREE(data);
}
void
d3d12_cmd_signature_cache_destroy(struct d3d12_context *ctx)
{
_mesa_hash_table_destroy(ctx->cmd_signature_cache, delete_entry);
}
@@ -0,0 +1,54 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_CMD_SIGNATURE_H
#define D3D12_CMD_SIGNATURE_H
#include "d3d12_context.h"
struct d3d12_cmd_signature_key {
uint8_t compute:1;
uint8_t indexed:1;
uint8_t draw_or_dispatch_params:1;
/* 5 bits padding */
uint8_t params_root_const_param;
uint8_t params_root_const_offset;
/* 8 bits padding */
unsigned multi_draw_stride;
/* Will be zero if no constant/resource updates in the arg buffer */
ID3D12RootSignature *root_sig;
};
void
d3d12_cmd_signature_cache_init(struct d3d12_context *ctx);
void
d3d12_cmd_signature_cache_destroy(struct d3d12_context *ctx);
ID3D12CommandSignature *
d3d12_get_cmd_signature(struct d3d12_context *ctx,
const struct d3d12_cmd_signature_key *key);
#endif
+156
View File
@@ -0,0 +1,156 @@
/*
* Copyright © Yonggang Luo
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_COMMON_STATE_H
#define D3D12_COMMON_STATE_H
#pragma once
#include <wsl/winadapter.h>
#define D3D12_IGNORE_SDK_LAYERS
#ifndef _GAMING_XBOX
#include <directx/d3d12.h>
#include <directx/d3d12video.h>
#elif defined(__cplusplus)
#ifdef _GAMING_XBOX_SCARLETT
#include <d3d12_xs.h>
#include <d3d12video_xs.h>
#else
#include <d3d12_x.h>
#include <d3d12video_x.h>
#endif
#ifdef IID_PPV_ARGS
#undef IID_PPV_ARGS
#endif
#define IID_PPV_ARGS IID_GRAPHICS_PPV_ARGS
#define D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT (D3D12_HEAP_FLAGS) 0x800
#endif /* _GAMING_XBOX */
#ifndef D3D12_TEXTURE_DATA_PITCH_ALIGNMENT
#define D3D12_TEXTURE_DATA_PITCH_ALIGNMENT D3D12XBOX_TEXTURE_DATA_PITCH_ALIGNMENT
#endif /* D3D12_TEXTURE_DATA_PITCH_ALIGNMENT */
#if defined(__cplusplus)
#if !defined(_WIN32) || defined(_MSC_VER)
inline D3D12_CPU_DESCRIPTOR_HANDLE
GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
return heap->GetCPUDescriptorHandleForHeapStart();
}
inline D3D12_GPU_DESCRIPTOR_HANDLE
GetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
return heap->GetGPUDescriptorHandleForHeapStart();
}
D3D12_HEAP_DESC
inline GetDesc(ID3D12Heap* heap)
{
return heap->GetDesc();
}
inline D3D12_RESOURCE_DESC
GetDesc(ID3D12Resource *res)
{
return res->GetDesc();
}
inline D3D12_HEAP_PROPERTIES
GetCustomHeapProperties(ID3D12Device *dev, D3D12_HEAP_TYPE type)
{
return dev->GetCustomHeapProperties(0, type);
}
inline LUID
GetAdapterLuid(ID3D12Device *dev)
{
return dev->GetAdapterLuid();
}
inline D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC
GetOutputStreamDesc(ID3D12VideoProcessor *proc)
{
return proc->GetOutputStreamDesc();
}
inline D3D12_RESOURCE_ALLOCATION_INFO
GetResourceAllocationInfo(ID3D12Device *dev, UINT visibleMask, UINT numResourceDescs, const D3D12_RESOURCE_DESC *pResourceDescs)
{
return dev->GetResourceAllocationInfo(visibleMask, numResourceDescs, pResourceDescs);
}
#else
inline D3D12_CPU_DESCRIPTOR_HANDLE
GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
D3D12_CPU_DESCRIPTOR_HANDLE ret;
heap->GetCPUDescriptorHandleForHeapStart(&ret);
return ret;
}
inline D3D12_GPU_DESCRIPTOR_HANDLE
GetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
D3D12_GPU_DESCRIPTOR_HANDLE ret;
heap->GetGPUDescriptorHandleForHeapStart(&ret);
return ret;
}
D3D12_HEAP_DESC
inline GetDesc(ID3D12Heap* heap)
{
D3D12_HEAP_DESC ret;
heap->GetDesc(&ret);
return ret;
}
inline D3D12_RESOURCE_DESC
GetDesc(ID3D12Resource *res)
{
D3D12_RESOURCE_DESC ret;
res->GetDesc(&ret);
return ret;
}
inline D3D12_HEAP_PROPERTIES
GetCustomHeapProperties(ID3D12Device *dev, D3D12_HEAP_TYPE type)
{
D3D12_HEAP_PROPERTIES ret;
dev->GetCustomHeapProperties(&ret, 0, type);
return ret;
}
inline LUID
GetAdapterLuid(ID3D12Device *dev)
{
LUID ret;
dev->GetAdapterLuid(&ret);
return ret;
}
inline D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC
GetOutputStreamDesc(ID3D12VideoProcessor *proc)
{
D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC ret;
proc->GetOutputStreamDesc(&ret);
return ret;
}
inline D3D12_RESOURCE_ALLOCATION_INFO
GetResourceAllocationInfo(ID3D12Device *dev, UINT visibleMask, UINT numResourceDescs, const D3D12_RESOURCE_DESC *pResourceDescs)
{
D3D12_RESOURCE_ALLOCATION_INFO ret;
dev->GetResourceAllocationInfo(&ret, visibleMask, numResourceDescs, pResourceDescs);
return ret;
}
#endif
#endif
#endif
File diff suppressed because it is too large. Load diff
+334
View File
@@ -0,0 +1,334 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_COMPILER_H
#define D3D12_COMPILER_H
#include "d3d12_common.h"
#include "dxil_nir_lower_int_samplers.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "compiler/shader_info.h"
#include "nir.h"
struct pipe_screen;
struct d3d12_context;
struct d3d12_screen;
#ifdef __cplusplus
extern "C" {
#endif
enum d3d12_state_var {
D3D12_STATE_VAR_Y_FLIP = 0,
D3D12_STATE_VAR_PT_SPRITE,
D3D12_STATE_VAR_DRAW_PARAMS,
D3D12_STATE_VAR_DEPTH_TRANSFORM,
D3D12_STATE_VAR_DEFAULT_INNER_TESS_LEVEL,
D3D12_STATE_VAR_DEFAULT_OUTER_TESS_LEVEL,
D3D12_STATE_VAR_PATCH_VERTICES_IN,
D3D12_MAX_GRAPHICS_STATE_VARS,
D3D12_STATE_VAR_NUM_WORKGROUPS = 0,
D3D12_STATE_VAR_TRANSFORM_GENERIC0,
D3D12_STATE_VAR_TRANSFORM_GENERIC1,
D3D12_MAX_COMPUTE_STATE_VARS,
D3D12_MAX_STATE_VARS = MAX2(D3D12_MAX_GRAPHICS_STATE_VARS, D3D12_MAX_COMPUTE_STATE_VARS)
};
#define D3D12_MAX_POINT_SIZE 255.0f
void
d3d12_varying_cache_init(struct d3d12_screen *ctx);
void
d3d12_varying_cache_destroy(struct d3d12_screen *ctx);
struct d3d12_varying_info {
struct {
const struct glsl_type *types[4];
uint8_t location_frac_mask:4;
uint8_t patch:1;
struct {
unsigned interpolation:3; // INTERP_MODE_COUNT = 5
unsigned driver_location:6; // VARYING_SLOT_MAX = 64
unsigned compact:1;
unsigned always_active_io:1;
} vars[4];
} slots[VARYING_SLOT_MAX];
uint64_t mask;
uint32_t hash;
uint32_t max;
};
struct d3d12_image_format_conversion_info {
enum pipe_format view_format, emulated_format;
};
struct d3d12_image_format_conversion_info_arr {
unsigned n_images;
struct d3d12_image_format_conversion_info* image_format_conversion;
};
struct d3d12_shader_key {
uint32_t hash;
mesa_shader_stage stage;
uint64_t next_varying_inputs;
uint64_t prev_varying_outputs;
BITSET_WORD *next_varying_frac_inputs;
BITSET_WORD *prev_varying_frac_outputs;
union {
struct {
unsigned last_vertex_processing_stage : 1;
unsigned invert_depth : 16;
unsigned halfz : 1;
unsigned samples_int_textures : 1;
unsigned input_clip_size : 4;
unsigned next_has_frac_inputs : 1;
unsigned prev_has_frac_outputs : 1;
};
uint32_t common_all;
};
unsigned tex_saturate_s : PIPE_MAX_SAMPLERS;
unsigned tex_saturate_r : PIPE_MAX_SAMPLERS;
unsigned tex_saturate_t : PIPE_MAX_SAMPLERS;
union {
struct {
unsigned needs_format_emulation:1;
enum pipe_format format_conversion[PIPE_MAX_ATTRIBS];
} vs;
union {
struct {
unsigned sprite_coord_enable:24;
unsigned sprite_origin_upper_left:1;
unsigned point_pos_stream_out:1;
unsigned writes_psize:1;
unsigned point_size_per_vertex:1;
unsigned aa_point:1;
unsigned stream_output_factor:3;
unsigned primitive_id:1;
unsigned triangle_strip:1;
};
uint64_t all;
} gs;
struct {
union {
struct {
uint32_t next_patch_inputs;
unsigned primitive_mode:2;
unsigned ccw:1;
unsigned point_mode:1;
unsigned spacing:2;
unsigned patch_vertices_in:5;
};
uint64_t all;
};
} hs;
struct {
unsigned tcs_vertices_out;
uint32_t prev_patch_outputs;
} ds;
union {
struct {
unsigned missing_dual_src_outputs : 2;
unsigned frag_result_color_lowering : 4;
unsigned cast_to_uint : 1;
unsigned cast_to_int : 1;
unsigned provoking_vertex : 2;
unsigned manual_depth_range : 1;
unsigned polygon_stipple : 1;
unsigned remap_front_facing : 1;
unsigned multisample_disabled : 1;
};
unsigned short all;
} fs;
struct {
unsigned workgroup_size[3];
} cs;
};
int n_texture_states;
dxil_wrap_sampler_state *tex_wrap_states;
dxil_texture_swizzle_state swizzle_state[PIPE_MAX_SHADER_SAMPLER_VIEWS];
enum compare_func sampler_compare_funcs[PIPE_MAX_SHADER_SAMPLER_VIEWS];
unsigned n_images;
struct d3d12_image_format_conversion_info image_format_conversion[PIPE_MAX_SHADER_IMAGES];
};
struct d3d12_shader {
void *bytecode;
size_t bytecode_length;
nir_shader *nir;
/* UBOs can be sparse, if there's no uniforms then ubo0 is unused, and state vars are an internal ubo */
uint32_t begin_ubo_binding;
uint32_t end_ubo_binding;
struct {
enum d3d12_state_var var;
unsigned offset;
} state_vars[D3D12_MAX_STATE_VARS];
unsigned num_state_vars;
size_t state_vars_size;
bool state_vars_used;
/* Samplers/textures can be sparse for some internal shaders */
struct {
uint32_t dimension;
} srv_bindings[PIPE_MAX_SHADER_SAMPLER_VIEWS];
uint32_t begin_srv_binding;
uint32_t end_srv_binding;
/* Images and SSBOs are never sparse */
struct {
uint32_t dimension;
} uav_bindings[PIPE_MAX_SHADER_IMAGES];
unsigned pstipple_binding;
struct d3d12_shader_key key;
struct d3d12_shader *next_variant;
};
struct d3d12_gs_variant_key
{
union {
struct {
unsigned passthrough:1;
unsigned provoking_vertex:3;
unsigned alternate_tri:1;
unsigned fill_mode:2;
unsigned cull_mode:2;
unsigned has_front_face:1;
unsigned front_ccw:1;
unsigned edge_flag_fix:1;
unsigned flatshade_first:1;
};
uint64_t all;
};
uint64_t flat_varyings;
struct d3d12_varying_info *varyings;
};
struct d3d12_tcs_variant_key
{
unsigned vertices_out;
struct d3d12_varying_info *varyings;
};
struct d3d12_shader_selector {
mesa_shader_stage stage;
const nir_shader *initial;
struct d3d12_varying_info *initial_output_vars;
struct d3d12_varying_info *initial_input_vars;
struct d3d12_shader *first;
struct d3d12_shader *current;
struct pipe_stream_output_info so_info;
unsigned samples_int_textures:1;
unsigned compare_with_lod_bias_grad:1;
unsigned workgroup_size_variable:1;
unsigned has_frac_inputs:1;
unsigned has_frac_outputs:1;
BITSET_DECLARE(varying_frac_inputs, 64 * 4);
BITSET_DECLARE(varying_frac_outputs, 64 * 4);
bool is_variant;
union {
struct d3d12_gs_variant_key gs_key;
struct d3d12_tcs_variant_key tcs_key;
};
};
struct d3d12_shader_selector *
d3d12_create_shader(struct d3d12_context *ctx,
mesa_shader_stage stage,
const struct pipe_shader_state *shader);
struct d3d12_shader_selector *
d3d12_create_compute_shader(struct d3d12_context *ctx,
const struct pipe_compute_state *shader);
void
d3d12_shader_free(struct d3d12_shader_selector *shader);
void
d3d12_select_shader_variants(struct d3d12_context *ctx,
const struct pipe_draw_info *dinfo);
void
d3d12_select_compute_shader_variants(struct d3d12_context *ctx,
const struct pipe_grid_info *info);
void
d3d12_gs_variant_cache_init(struct d3d12_context *ctx);
void
d3d12_gs_variant_cache_destroy(struct d3d12_context *ctx);
struct d3d12_shader_selector *
d3d12_get_gs_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key);
void
d3d12_tcs_variant_cache_init(struct d3d12_context *ctx);
void
d3d12_tcs_variant_cache_destroy(struct d3d12_context *ctx);
struct d3d12_shader_selector *
d3d12_get_tcs_variant(struct d3d12_context *ctx, struct d3d12_tcs_variant_key *key);
unsigned
missing_dual_src_outputs(struct d3d12_context* ctx);
bool
has_flat_varyings(struct d3d12_context* ctx);
bool
d3d12_compare_varying_info(const struct d3d12_varying_info *expect, const struct d3d12_varying_info *have);
bool
manual_depth_range(struct d3d12_context* ctx);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,513 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_compute_transforms.h"
#include "d3d12_nir_passes.h"
#include "d3d12_query.h"
#include "d3d12_screen.h"
#include "nir.h"
#include "nir_builder.h"
#include "util/u_memory.h"
nir_shader *
get_indirect_draw_base_vertex_transform(const nir_shader_compiler_options *options, const d3d12_compute_transform_key *args)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, options, "TransformIndirectDrawBaseVertex");
if (args->base_vertex.dynamic_count) {
nir_variable *count_ubo = nir_variable_create(b.shader, nir_var_mem_ubo,
glsl_uint_type(), "in_count");
count_ubo->data.driver_location = 0;
}
nir_variable *input_ssbo = nir_variable_create(b.shader, nir_var_mem_ssbo,
glsl_array_type(glsl_uint_type(), 0, 0), "input");
nir_variable *output_ssbo = nir_variable_create(b.shader, nir_var_mem_ssbo,
input_ssbo->type, "output");
input_ssbo->data.driver_location = 0;
output_ssbo->data.driver_location = 1;
nir_def *draw_id = nir_channel(&b, nir_load_global_invocation_id(&b, 32), 0);
if (args->base_vertex.dynamic_count) {
nir_def *count = nir_load_ubo(&b, 1, 32, nir_imm_int(&b, 1), nir_imm_int(&b, 0),
(gl_access_qualifier)0, 4, 0, 0, 4);
nir_push_if(&b, nir_ilt(&b, draw_id, count));
}
nir_variable *stride_ubo = NULL;
nir_def *in_stride_offset_and_base_drawid = d3d12_get_state_var(&b, D3D12_STATE_VAR_TRANSFORM_GENERIC0, "d3d12_Stride",
glsl_uvec4_type(), &stride_ubo);
nir_def *in_offset = nir_iadd(&b, nir_channel(&b, in_stride_offset_and_base_drawid, 1),
nir_imul(&b, nir_channel(&b, in_stride_offset_and_base_drawid, 0), draw_id));
nir_def *in_data0 = nir_load_ssbo(&b, 4, 32, nir_imm_int(&b, 0), in_offset, (gl_access_qualifier)0, 4, 0);
nir_def *in_data1 = NULL;
nir_def *base_vertex = NULL, *base_instance = NULL;
if (args->base_vertex.indexed) {
nir_def *in_offset1 = nir_iadd(&b, in_offset, nir_imm_int(&b, 16));
in_data1 = nir_load_ssbo(&b, 1, 32, nir_imm_int(&b, 0), in_offset1, (gl_access_qualifier)0, 4, 0);
base_vertex = nir_channel(&b, in_data0, 3);
base_instance = in_data1;
} else {
base_vertex = nir_channel(&b, in_data0, 2);
base_instance = nir_channel(&b, in_data0, 3);
}
/* 4 additional uints for base vertex, base instance, draw ID, and a bool for indexed draw */
unsigned out_stride = sizeof(uint32_t) * ((args->base_vertex.indexed ? 5 : 4) + 4);
nir_def *out_offset = nir_imul(&b, draw_id, nir_imm_int(&b, out_stride));
nir_def *out_data0 = nir_vec4(&b, base_vertex, base_instance,
nir_iadd(&b, draw_id, nir_channel(&b, in_stride_offset_and_base_drawid, 2)),
nir_imm_int(&b, args->base_vertex.indexed ? -1 : 0));
nir_def *out_data1 = in_data0;
nir_store_ssbo(&b, out_data0, nir_imm_int(&b, 1), out_offset, 0xf, (gl_access_qualifier)0, 4, 0);
nir_store_ssbo(&b, out_data1, nir_imm_int(&b, 1), nir_iadd(&b, out_offset, nir_imm_int(&b, 16)),
(1u << out_data1->num_components) - 1, (gl_access_qualifier)0, 4, 0);
if (args->base_vertex.indexed)
nir_store_ssbo(&b, in_data1, nir_imm_int(&b, 1), nir_iadd(&b, out_offset, nir_imm_int(&b, 32)), 1, (gl_access_qualifier)0, 4, 0);
if (args->base_vertex.dynamic_count)
nir_pop_if(&b, NULL);
nir_validate_shader(b.shader, "creation");
b.shader->info.num_ssbos = 2;
b.shader->info.num_ubos = (args->base_vertex.dynamic_count ? 1 : 0);
return b.shader;
}
static struct nir_shader *
get_fake_so_buffer_copy_back(const nir_shader_compiler_options *options, const d3d12_compute_transform_key *key)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, options, "FakeSOBufferCopyBack");
nir_variable *output_so_data_var = nir_variable_create(b.shader, nir_var_mem_ssbo,
glsl_array_type(glsl_uint_type(), 0, 0), "output_data");
nir_variable *input_so_data_var = nir_variable_create(b.shader, nir_var_mem_ssbo, output_so_data_var->type, "input_data");
output_so_data_var->data.driver_location = 0;
input_so_data_var->data.driver_location = 1;
/* UBO is [fake SO filled size, fake SO vertex count, 1, 1, original SO filled size] */
nir_variable *input_ubo = nir_variable_create(b.shader, nir_var_mem_ubo,
glsl_array_type(glsl_uint_type(), 5, 0), "input_ubo");
input_ubo->data.driver_location = 0;
nir_def *original_so_filled_size = nir_load_ubo(&b, 1, 32, nir_imm_int(&b, 0), nir_imm_int(&b, 4 * sizeof(uint32_t)),
(gl_access_qualifier)0, 4, 0, 4 * sizeof(uint32_t), 4);
nir_variable *state_var = nullptr;
nir_def *fake_so_multiplier = d3d12_get_state_var(&b, D3D12_STATE_VAR_TRANSFORM_GENERIC0, "fake_so_multiplier", glsl_uint_type(), &state_var);
nir_def *vertex_offset = nir_imul(&b, nir_imm_int(&b, key->fake_so_buffer_copy_back.stride),
nir_channel(&b, nir_load_global_invocation_id(&b, 32), 0));
nir_def *output_offset_base = nir_iadd(&b, original_so_filled_size, vertex_offset);
nir_def *input_offset_base = nir_imul(&b, vertex_offset, fake_so_multiplier);
for (unsigned i = 0; i < key->fake_so_buffer_copy_back.num_ranges; ++i) {
auto& output = key->fake_so_buffer_copy_back.ranges[i];
assert(output.size % 4 == 0 && output.offset % 4 == 0);
nir_def *field_offset = nir_imm_int(&b, output.offset);
nir_def *output_offset = nir_iadd(&b, output_offset_base, field_offset);
nir_def *input_offset = nir_iadd(&b, input_offset_base, field_offset);
for (unsigned loaded = 0; loaded < output.size; loaded += 16) {
unsigned to_load = MIN2(output.size, 16);
unsigned components = to_load / 4;
nir_def *loaded_data = nir_load_ssbo(&b, components, 32, nir_imm_int(&b, 1),
nir_iadd(&b, input_offset, nir_imm_int(&b, loaded)), (gl_access_qualifier)0, 4, 0);
nir_store_ssbo(&b, loaded_data, nir_imm_int(&b, 0),
nir_iadd(&b, output_offset, nir_imm_int(&b, loaded)), (1u << components) - 1, (gl_access_qualifier)0, 4, 0);
}
}
nir_validate_shader(b.shader, "creation");
b.shader->info.num_ssbos = 2;
b.shader->info.num_ubos = 1;
return b.shader;
}
static struct nir_shader *
get_fake_so_buffer_vertex_count(const nir_shader_compiler_options *options)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, options, "FakeSOBufferVertexCount");
nir_variable_create(b.shader, nir_var_mem_ssbo, glsl_array_type(glsl_uint_type(), 0, 0), "fake_so");
nir_def *fake_buffer_filled_size = nir_load_ssbo(&b, 1, 32, nir_imm_int(&b, 0), nir_imm_int(&b, 0), (gl_access_qualifier)0, 4, 0);
nir_variable *real_so_var = nir_variable_create(b.shader, nir_var_mem_ssbo,
glsl_array_type(glsl_uint_type(), 0, 0), "real_so");
real_so_var->data.driver_location = 1;
nir_def *real_buffer_filled_size = nir_load_ssbo(&b, 1, 32, nir_imm_int(&b, 1), nir_imm_int(&b, 0), (gl_access_qualifier)0, 4, 0);
nir_variable *state_var = nullptr;
nir_def *state_var_data = d3d12_get_state_var(&b, D3D12_STATE_VAR_TRANSFORM_GENERIC0, "state_var", glsl_uvec4_type(), &state_var);
nir_def *stride = nir_channel(&b, state_var_data, 0);
nir_def *fake_so_multiplier = nir_channel(&b, state_var_data, 1);
nir_def *real_so_bytes_added = nir_idiv(&b, fake_buffer_filled_size, fake_so_multiplier);
nir_def *vertex_count = nir_idiv(&b, real_so_bytes_added, stride);
nir_def *to_write_to_fake_buffer = nir_vec4(&b, vertex_count, nir_imm_int(&b, 1), nir_imm_int(&b, 1), real_buffer_filled_size);
nir_store_ssbo(&b, to_write_to_fake_buffer, nir_imm_int(&b, 0), nir_imm_int(&b, 4), 0xf, (gl_access_qualifier)0, 4, 0);
nir_def *updated_filled_size = nir_iadd(&b, real_buffer_filled_size, real_so_bytes_added);
nir_store_ssbo(&b, updated_filled_size, nir_imm_int(&b, 1), nir_imm_int(&b, 0), 1, (gl_access_qualifier)0, 4, 0);
nir_validate_shader(b.shader, "creation");
b.shader->info.num_ssbos = 2;
b.shader->info.num_ubos = 0;
return b.shader;
}
static struct nir_shader *
get_draw_auto(const nir_shader_compiler_options *options)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, options, "DrawAuto");
nir_variable_create(b.shader, nir_var_mem_ssbo, glsl_array_type(glsl_uint_type(), 0, 0), "ssbo");
nir_def *buffer_filled_size = nir_load_ssbo(&b, 1, 32, nir_imm_int(&b, 0), nir_imm_int(&b, 0), (gl_access_qualifier)0, 4, 0);
nir_variable *state_var = nullptr;
nir_def *state_var_data = d3d12_get_state_var(&b, D3D12_STATE_VAR_TRANSFORM_GENERIC0, "state_var", glsl_uvec4_type(), &state_var);
nir_def *stride = nir_channel(&b, state_var_data, 0);
nir_def *vb_offset = nir_channel(&b, state_var_data, 1);
nir_def *vb_bytes = nir_bcsel(&b, nir_ilt(&b, vb_offset, buffer_filled_size),
nir_isub(&b, buffer_filled_size, vb_offset), nir_imm_int(&b, 0));
nir_def *vertex_count = nir_idiv(&b, vb_bytes, stride);
nir_def *to_write = nir_vec4(&b, vertex_count, nir_imm_int(&b, 1), nir_imm_int(&b, 0), nir_imm_int(&b, 0));
nir_store_ssbo(&b, to_write, nir_imm_int(&b, 0), nir_imm_int(&b, 4), 0xf, (gl_access_qualifier)0, 4, 0);
nir_validate_shader(b.shader, "creation");
b.shader->info.num_ssbos = 1;
b.shader->info.num_ubos = 0;
return b.shader;
}
static struct nir_shader *
get_query_resolve(const nir_shader_compiler_options *options, const d3d12_compute_transform_key *key)
{
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, options, "QueryResolve");
uint32_t bit_size = key->query_resolve.is_64bit ? 64 : 32;
const struct glsl_type *value_type = glsl_uintN_t_type(bit_size);
assert(!key->query_resolve.is_resolve_in_place ||
(key->query_resolve.is_64bit && key->query_resolve.num_subqueries == 1));
assert(key->query_resolve.num_subqueries == 1 ||
key->query_resolve.pipe_query_type == PIPE_QUERY_PRIMITIVES_GENERATED ||
key->query_resolve.pipe_query_type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE);
assert(key->query_resolve.num_subqueries <= 4);
nir_variable *inputs[4];
for (uint32_t i = 0; i < key->query_resolve.num_subqueries; ++i) {
/* Inputs are always 64-bit */
inputs[i] = nir_variable_create(b.shader, nir_var_mem_ssbo, glsl_array_type(glsl_uint64_t_type(), 0, 8), "input");
inputs[i]->data.binding = i;
}
nir_variable *output = inputs[0];
if (!key->query_resolve.is_resolve_in_place) {
output = nir_variable_create(b.shader, nir_var_mem_ssbo, glsl_array_type(value_type, 0, bit_size / 8), "output");
output->data.binding = key->query_resolve.num_subqueries;
}
/* How many entries in each sub-query is passed via root constants */
nir_variable *state_var = nullptr, *state_var1 = nullptr;
nir_def *state_var_data = d3d12_get_state_var(&b, D3D12_STATE_VAR_TRANSFORM_GENERIC0, "state_var", glsl_uvec4_type(), &state_var);
nir_def *state_var_data1 = d3d12_get_state_var(&b, D3D12_STATE_VAR_TRANSFORM_GENERIC1, "state_var1", glsl_uvec4_type(), &state_var1);
/* For in-place resolves, we resolve each field of the query. Otherwise, resolve one field into the dest */
nir_variable *results[sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) / sizeof(UINT64)];
uint32_t num_result_values = 1;
if (key->query_resolve.is_resolve_in_place) {
if (key->query_resolve.pipe_query_type == PIPE_QUERY_PIPELINE_STATISTICS)
num_result_values = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) / sizeof(UINT64);
else if (key->query_resolve.pipe_query_type == PIPE_QUERY_SO_STATISTICS)
num_result_values = sizeof(D3D12_QUERY_DATA_SO_STATISTICS) / sizeof(UINT64);
}
uint32_t var_bit_size = key->query_resolve.pipe_query_type == PIPE_QUERY_TIME_ELAPSED ||
key->query_resolve.pipe_query_type == PIPE_QUERY_TIMESTAMP ? 64 : bit_size;
for (uint32_t i = 0; i < num_result_values; ++i) {
results[i] = nir_local_variable_create(b.impl, glsl_uintN_t_type(var_bit_size), "result");
nir_store_var(&b, results[i], nir_imm_intN_t(&b, 0, var_bit_size), 1);
}
/* For each subquery... */
for (uint32_t i = 0; i < key->query_resolve.num_subqueries; ++i) {
nir_def *num_results = nir_channel(&b, state_var_data, i);
uint32_t subquery_index = key->query_resolve.num_subqueries == 1 ?
key->query_resolve.single_subquery_index : i;
uint32_t base_offset = 0;
uint32_t stride = 0;
switch (key->query_resolve.pipe_query_type) {
case PIPE_QUERY_OCCLUSION_COUNTER:
case PIPE_QUERY_OCCLUSION_PREDICATE:
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
case PIPE_QUERY_TIMESTAMP:
stride = 1;
break;
case PIPE_QUERY_TIME_ELAPSED:
stride = 2;
break;
case PIPE_QUERY_SO_STATISTICS:
case PIPE_QUERY_PRIMITIVES_EMITTED:
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
stride = sizeof(D3D12_QUERY_DATA_SO_STATISTICS) / sizeof(UINT64);
break;
case PIPE_QUERY_PRIMITIVES_GENERATED:
if (subquery_index == 0)
stride = sizeof(D3D12_QUERY_DATA_SO_STATISTICS) / sizeof(UINT64);
else
stride = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) / sizeof(UINT64);
if (!key->query_resolve.is_resolve_in_place) {
if (subquery_index == 1)
base_offset = offsetof(D3D12_QUERY_DATA_PIPELINE_STATISTICS, GSPrimitives) / sizeof(UINT64);
else if (subquery_index == 2)
base_offset = offsetof(D3D12_QUERY_DATA_PIPELINE_STATISTICS, IAPrimitives) / sizeof(UINT64);
}
break;
case PIPE_QUERY_PIPELINE_STATISTICS:
stride = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) / sizeof(UINT64);
break;
default:
UNREACHABLE("Unhandled query resolve");
}
if (!key->query_resolve.is_resolve_in_place && key->query_resolve.num_subqueries == 1)
base_offset = key->query_resolve.single_result_field_offset;
nir_def *base_array_index = nir_imm_int(&b, base_offset);
/* For each query result in this subquery... */
nir_variable *loop_counter = nir_local_variable_create(b.impl, glsl_uint_type(), "loop_counter");
nir_store_var(&b, loop_counter, nir_imm_int(&b, 0), 1);
nir_loop *loop = nir_push_loop(&b);
nir_def *loop_counter_value = nir_load_var(&b, loop_counter);
nir_break_if(&b, nir_ieq(&b, loop_counter_value, num_results));
/* For each field in the query result, accumulate */
nir_def *array_index = nir_iadd(&b, nir_imul_imm(&b, loop_counter_value, stride), base_array_index);
for (uint32_t j = 0; j < num_result_values; ++j) {
nir_def *new_value;
if (key->query_resolve.pipe_query_type == PIPE_QUERY_TIME_ELAPSED) {
assert(j == 0 && i == 0);
nir_def *start = nir_load_ssbo(&b, 1, 64, nir_imm_int(&b, i), nir_imul_imm(&b, array_index, 8));
nir_def *end = nir_load_ssbo(&b, 1, 64, nir_imm_int(&b, i), nir_imul_imm(&b, nir_iadd_imm(&b, array_index, 1), 8));
new_value = nir_iadd(&b, nir_load_var(&b, results[j]), nir_isub(&b, end, start));
} else if (key->query_resolve.pipe_query_type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE ||
key->query_resolve.pipe_query_type == PIPE_QUERY_SO_OVERFLOW_PREDICATE) {
/* These predicates are true if the primitives emitted != primitives stored */
assert(j == 0);
nir_def *val_a = nir_load_ssbo(&b, 1, 64, nir_imm_int(&b, i), nir_imul_imm(&b, array_index, 8));
nir_def *val_b = nir_load_ssbo(&b, 1, 64, nir_imm_int(&b, i), nir_imul_imm(&b, nir_iadd_imm(&b, array_index, 1), 8));
new_value = nir_ior(&b, nir_load_var(&b, results[j]), nir_u2uN(&b, nir_ine(&b, val_a, val_b), var_bit_size));
} else {
new_value = nir_u2uN(&b, nir_load_ssbo(&b, 1, 64, nir_imm_int(&b, i), nir_imul_imm(&b, nir_iadd_imm(&b, array_index, j), 8)), var_bit_size);
new_value = nir_iadd(&b, nir_load_var(&b, results[j]), new_value);
}
nir_store_var(&b, results[j], new_value, 1);
}
nir_store_var(&b, loop_counter, nir_iadd_imm(&b, loop_counter_value, 1), 1);
nir_pop_loop(&b, loop);
}
/* Results are accumulated, now store the final values */
nir_def *output_base_index = nir_channel(&b, state_var_data1, 0);
for (uint32_t i = 0; i < num_result_values; ++i) {
/* When resolving in-place, resolve each field, otherwise just write the one result */
uint32_t field_offset = key->query_resolve.is_resolve_in_place ? i : 0;
/* When resolving time elapsed in-place, write [0, time], as the only special case */
if (key->query_resolve.is_resolve_in_place &&
key->query_resolve.pipe_query_type == PIPE_QUERY_TIME_ELAPSED) {
nir_store_ssbo(&b, nir_imm_int64(&b, 0), nir_imm_int(&b, output->data.binding),
nir_imul_imm(&b, output_base_index, bit_size / 8), 1, (gl_access_qualifier)0, bit_size / 8, 0);
field_offset++;
}
nir_def *result_val = nir_load_var(&b, results[i]);
if (!key->query_resolve.is_resolve_in_place &&
(key->query_resolve.pipe_query_type == PIPE_QUERY_TIME_ELAPSED ||
key->query_resolve.pipe_query_type == PIPE_QUERY_TIMESTAMP)) {
result_val = nir_f2u64(&b, nir_fmul_imm(&b, nir_u2f32(&b, result_val), key->query_resolve.timestamp_multiplier));
if (!key->query_resolve.is_64bit) {
nir_alu_type rounding_type = key->query_resolve.is_signed ? nir_type_int : nir_type_uint;
nir_alu_type src_round = (nir_alu_type)(rounding_type | 64);
nir_alu_type dst_round = (nir_alu_type)(rounding_type | bit_size);
result_val = nir_convert_alu_types(&b, bit_size, result_val, src_round, dst_round, nir_rounding_mode_undef, true);
}
}
nir_store_ssbo(&b, result_val, nir_imm_int(&b, output->data.binding),
nir_imul_imm(&b, nir_iadd_imm(&b, output_base_index, field_offset), bit_size / 8),
1, (gl_access_qualifier)0, bit_size / 8, 0);
}
nir_validate_shader(b.shader, "creation");
b.shader->info.num_ssbos = key->query_resolve.num_subqueries + !key->query_resolve.is_resolve_in_place;
b.shader->info.num_ubos = 0;
NIR_PASS(_, b.shader, nir_lower_convert_alu_types, NULL);
return b.shader;
}
static struct nir_shader *
create_compute_transform(const nir_shader_compiler_options *options, const d3d12_compute_transform_key *key)
{
switch (key->type) {
case d3d12_compute_transform_type::base_vertex:
return get_indirect_draw_base_vertex_transform(options, key);
case d3d12_compute_transform_type::fake_so_buffer_copy_back:
return get_fake_so_buffer_copy_back(options, key);
case d3d12_compute_transform_type::fake_so_buffer_vertex_count:
return get_fake_so_buffer_vertex_count(options);
case d3d12_compute_transform_type::draw_auto:
return get_draw_auto(options);
case d3d12_compute_transform_type::query_resolve:
return get_query_resolve(options, key);
default:
UNREACHABLE("Invalid transform");
}
}
struct compute_transform
{
d3d12_compute_transform_key key;
d3d12_shader_selector *shader;
};
d3d12_shader_selector *
d3d12_get_compute_transform(struct d3d12_context *ctx, const d3d12_compute_transform_key *key)
{
struct hash_entry *entry = _mesa_hash_table_search(ctx->compute_transform_cache, key);
if (!entry) {
compute_transform *data = (compute_transform *)MALLOC(sizeof(compute_transform));
if (!data)
return NULL;
const nir_shader_compiler_options *options = &d3d12_screen(ctx->base.screen)->nir_options;
memcpy(&data->key, key, sizeof(*key));
nir_shader *s = create_compute_transform(options, key);
if (!s) {
FREE(data);
return NULL;
}
struct pipe_compute_state shader_args = { PIPE_SHADER_IR_NIR, s };
data->shader = d3d12_create_compute_shader(ctx, &shader_args);
if (!data->shader) {
ralloc_free(s);
FREE(data);
return NULL;
}
data->shader->is_variant = true;
entry = _mesa_hash_table_insert(ctx->compute_transform_cache, &data->key, data);
assert(entry);
}
return ((struct compute_transform *)entry->data)->shader;
}
static uint32_t
hash_compute_transform_key(const void *key)
{
return _mesa_hash_data(key, sizeof(struct d3d12_compute_transform_key));
}
static bool
equals_compute_transform_key(const void *a, const void *b)
{
return memcmp(a, b, sizeof(struct d3d12_compute_transform_key)) == 0;
}
void
d3d12_compute_transform_cache_init(struct d3d12_context *ctx)
{
ctx->compute_transform_cache = _mesa_hash_table_create(NULL,
hash_compute_transform_key,
equals_compute_transform_key);
}
static void
delete_entry(struct hash_entry *entry)
{
struct compute_transform *data = (struct compute_transform *)entry->data;
d3d12_shader_free(data->shader);
FREE(data);
}
void
d3d12_compute_transform_cache_destroy(struct d3d12_context *ctx)
{
_mesa_hash_table_destroy(ctx->compute_transform_cache, delete_entry);
}
void
d3d12_save_compute_transform_state(struct d3d12_context *ctx, d3d12_compute_transform_save_restore *save)
{
if (ctx->current_predication)
ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
memset(save, 0, sizeof(*save));
save->cs = ctx->compute_state;
pipe_resource_reference(&save->cbuf0.buffer, ctx->cbufs[MESA_SHADER_COMPUTE][1].buffer);
save->cbuf0 = ctx->cbufs[MESA_SHADER_COMPUTE][1];
for (unsigned i = 0; i < ARRAY_SIZE(save->ssbos); ++i) {
pipe_resource_reference(&save->ssbos[i].buffer, ctx->ssbo_views[MESA_SHADER_COMPUTE][i].buffer);
save->ssbos[i] = ctx->ssbo_views[MESA_SHADER_COMPUTE][i];
}
save->queries_disabled = ctx->queries_disabled;
ctx->base.set_active_query_state(&ctx->base, false);
}
void
d3d12_restore_compute_transform_state(struct d3d12_context *ctx, d3d12_compute_transform_save_restore *save)
{
ctx->base.set_active_query_state(&ctx->base, !save->queries_disabled);
ctx->base.bind_compute_state(&ctx->base, save->cs);
ctx->base.set_constant_buffer(&ctx->base, MESA_SHADER_COMPUTE, 1, &save->cbuf0);
ctx->base.set_shader_buffers(&ctx->base, MESA_SHADER_COMPUTE, 0, ARRAY_SIZE(save->ssbos), save->ssbos, (1u << ARRAY_SIZE(save->ssbos)) - 1);
if (ctx->current_predication)
d3d12_enable_predication(ctx);
}
@@ -0,0 +1,115 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_COMPUTE_TRANSFORMS_H
#define D3D12_COMPUTE_TRANSFORMS_H
#include "d3d12_context.h"
#include "d3d12_compiler.h"
enum class d3d12_compute_transform_type
{
/* Extract vertex shader draw params (base vertex, instance, draw ID) from
* a stream of indirect draw (indexed) params
*/
base_vertex,
/* Given an SO buffer's declaration in the key, copy filled items from a fake (multiplied)
* buffer into the original SO buffer, after the original filled size (loaded from the indirect
* arg buffer double-bound as a UBO), making sure to skip gaps
*/
fake_so_buffer_copy_back,
/* Append a fake SO buffer filed size with (vertex count, 1, 1, original filled size)
* for an indirect dispatch of the fake_so_buffer_copy_back transform, and also update
* the original filled size with the fake filled size
*/
fake_so_buffer_vertex_count,
/* Append a buffer filled size with (vertex count, 1, 0, 0) */
draw_auto,
/* Accumulate queries together and write a 32-bit or 64-bit result */
query_resolve,
max,
};
struct d3d12_compute_transform_key
{
d3d12_compute_transform_type type;
union
{
struct {
unsigned indexed : 1;
unsigned dynamic_count : 1;
} base_vertex;
struct {
uint16_t stride;
uint16_t num_ranges;
struct {
uint16_t offset;
uint16_t size;
} ranges[PIPE_MAX_SO_OUTPUTS];
} fake_so_buffer_copy_back;
struct {
/* true means the accumulation should be done as uint64, else uint32. */
uint8_t is_64bit : 1;
/* Indicates how many subqueries to accumulate together into a final result. When
* set to 1, single_subquery_index determines where the data comes from. */
uint8_t num_subqueries : 3;
uint8_t pipe_query_type : 4;
/* true means output is written where input[0] was, else output is a separate buffer.
* true also means all fields are accumulated, else single_result_field_offset determines
* which field is resolved. Implies num_subqueries == 1. */
uint8_t is_resolve_in_place : 1;
uint8_t single_subquery_index : 2;
uint8_t single_result_field_offset : 4;
uint8_t is_signed : 1;
float timestamp_multiplier;
} query_resolve;
};
};
d3d12_shader_selector *
d3d12_get_compute_transform(struct d3d12_context *ctx, const d3d12_compute_transform_key *key);
void
d3d12_compute_transform_cache_init(struct d3d12_context *ctx);
void
d3d12_compute_transform_cache_destroy(struct d3d12_context *ctx);
struct d3d12_compute_transform_save_restore
{
struct d3d12_shader_selector *cs;
struct pipe_constant_buffer cbuf0;
struct pipe_shader_buffer ssbos[5];
bool queries_disabled;
};
void
d3d12_save_compute_transform_state(struct d3d12_context *ctx, d3d12_compute_transform_save_restore *save);
void
d3d12_restore_compute_transform_state(struct d3d12_context *ctx, d3d12_compute_transform_save_restore *save);
#endif
+430
View File
@@ -0,0 +1,430 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_CONTEXT_H
#define D3D12_CONTEXT_H
#include "d3d12_batch.h"
#include "d3d12_descriptor_pool.h"
#include "d3d12_pipeline_state.h"
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
#include "dxil_nir_lower_int_samplers.h"
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/list.h"
#include "util/slab.h"
#include "util/u_framebuffer.h"
#include "util/u_suballoc.h"
#include "util/u_threaded_context.h"
struct d3d12_context_queue_priority_manager;
#define D3D12_GFX_SHADER_STAGES (MESA_SHADER_STAGES - 1)
enum d3d12_dirty_flags
{
D3D12_DIRTY_NONE = 0,
D3D12_DIRTY_BLEND = (1 << 0),
D3D12_DIRTY_RASTERIZER = (1 << 1),
D3D12_DIRTY_ZSA = (1 << 2),
D3D12_DIRTY_VERTEX_ELEMENTS = (1 << 3),
D3D12_DIRTY_BLEND_COLOR = (1 << 4),
D3D12_DIRTY_STENCIL_REF = (1 << 5),
D3D12_DIRTY_SAMPLE_MASK = (1 << 6),
D3D12_DIRTY_VIEWPORT = (1 << 7),
D3D12_DIRTY_FRAMEBUFFER = (1 << 8),
D3D12_DIRTY_SCISSOR = (1 << 9),
D3D12_DIRTY_VERTEX_BUFFERS = (1 << 10),
D3D12_DIRTY_INDEX_BUFFER = (1 << 11),
D3D12_DIRTY_PRIM_MODE = (1 << 12),
D3D12_DIRTY_SHADER = (1 << 13),
D3D12_DIRTY_ROOT_SIGNATURE = (1 << 14),
D3D12_DIRTY_STREAM_OUTPUT = (1 << 15),
D3D12_DIRTY_STRIP_CUT_VALUE = (1 << 16),
D3D12_DIRTY_COMPUTE_SHADER = (1 << 17),
D3D12_DIRTY_COMPUTE_ROOT_SIGNATURE = (1 << 18),
};
enum d3d12_shader_dirty_flags
{
D3D12_SHADER_DIRTY_CONSTBUF = (1 << 0),
D3D12_SHADER_DIRTY_SAMPLER_VIEWS = (1 << 1),
D3D12_SHADER_DIRTY_SAMPLERS = (1 << 2),
D3D12_SHADER_DIRTY_SSBO = (1 << 3),
D3D12_SHADER_DIRTY_IMAGE = (1 << 4),
};
#define D3D12_DIRTY_GFX_PSO (D3D12_DIRTY_BLEND | D3D12_DIRTY_RASTERIZER | D3D12_DIRTY_ZSA | \
D3D12_DIRTY_FRAMEBUFFER | D3D12_DIRTY_SAMPLE_MASK | \
D3D12_DIRTY_VERTEX_ELEMENTS | D3D12_DIRTY_PRIM_MODE | \
D3D12_DIRTY_SHADER | D3D12_DIRTY_ROOT_SIGNATURE | \
D3D12_DIRTY_STRIP_CUT_VALUE | D3D12_DIRTY_STREAM_OUTPUT)
#define D3D12_DIRTY_COMPUTE_PSO (D3D12_DIRTY_COMPUTE_SHADER | D3D12_DIRTY_COMPUTE_ROOT_SIGNATURE)
#define D3D12_DIRTY_COMPUTE_MASK (D3D12_DIRTY_COMPUTE_SHADER | D3D12_DIRTY_COMPUTE_ROOT_SIGNATURE)
#define D3D12_DIRTY_GFX_MASK ~D3D12_DIRTY_COMPUTE_MASK
#define D3D12_SHADER_DIRTY_ALL (D3D12_SHADER_DIRTY_CONSTBUF | D3D12_SHADER_DIRTY_SAMPLER_VIEWS | \
D3D12_SHADER_DIRTY_SAMPLERS | D3D12_SHADER_DIRTY_SSBO | \
D3D12_SHADER_DIRTY_IMAGE)
enum d3d12_binding_type {
D3D12_BINDING_CONSTANT_BUFFER,
D3D12_BINDING_SHADER_RESOURCE_VIEW,
D3D12_BINDING_SAMPLER,
D3D12_BINDING_STATE_VARS,
D3D12_BINDING_SSBO,
D3D12_BINDING_IMAGE,
D3D12_NUM_BINDING_TYPES
};
struct d3d12_sampler_state {
struct d3d12_descriptor_handle handle, handle_without_shadow;
bool is_integer_texture;
bool is_shadow_sampler;
enum pipe_tex_wrap wrap_r;
enum pipe_tex_wrap wrap_s;
enum pipe_tex_wrap wrap_t;
enum pipe_tex_filter filter;
float lod_bias;
float min_lod, max_lod;
float border_color[4];
enum pipe_compare_func compare_func;
};
enum d3d12_blend_factor_flags {
D3D12_BLEND_FACTOR_NONE = 0,
D3D12_BLEND_FACTOR_COLOR = 1 << 0,
D3D12_BLEND_FACTOR_ALPHA = 1 << 1,
D3D12_BLEND_FACTOR_ANY = 1 << 2,
};
struct d3d12_sampler_view {
struct pipe_sampler_view base;
struct d3d12_descriptor_handle handle;
unsigned mip_levels;
unsigned array_size;
unsigned texture_generation_id;
unsigned swizzle_override_r:3; /**< PIPE_SWIZZLE_x for red component */
unsigned swizzle_override_g:3; /**< PIPE_SWIZZLE_x for green component */
unsigned swizzle_override_b:3; /**< PIPE_SWIZZLE_x for blue component */
unsigned swizzle_override_a:3; /**< PIPE_SWIZZLE_x for alpha component */
};
static inline struct d3d12_sampler_view *
d3d12_sampler_view(struct pipe_sampler_view *pview)
{
return (struct d3d12_sampler_view *)pview;
}
struct d3d12_stream_output_target {
struct pipe_stream_output_target base;
struct pipe_resource *fill_buffer;
unsigned fill_buffer_offset;
};
struct d3d12_shader_state {
struct d3d12_shader *current;
unsigned state_dirty;
};
struct blitter_context;
struct primconvert_context;
#ifdef _WIN32
struct dxil_validator;
#endif
#ifdef __cplusplus
class ResourceStateManager;
#endif
#define D3D12_CONTEXT_NO_ID 0xffffffff
struct d3d12_context {
struct pipe_context base;
unsigned id;
struct slab_child_pool transfer_pool;
struct slab_child_pool transfer_pool_unsync;
struct list_head context_list_entry;
struct threaded_context *threaded_context;
struct d3d12_batch batches[8];
unsigned current_batch_idx;
struct util_dynarray recently_destroyed_bos;
struct util_dynarray barrier_scratch;
struct set *pending_barriers_bos;
struct util_dynarray local_pending_barriers_bos;
uint64_t submit_id;
ID3D12GraphicsCommandList *cmdlist;
ID3D12GraphicsCommandList2 *cmdlist2;
ID3D12GraphicsCommandList8 *cmdlist8;
ID3D12GraphicsCommandList *state_fixup_cmdlist;
struct hash_table_u64 *bo_state_table;
struct set *local_state_bos;
struct blitter_context *blitter;
uint flags;
bool queries_disabled;
bool has_commands;
#ifdef __cplusplus
ResourceStateManager *resource_state_manager;
#else
void *resource_state_manager; /* opaque pointer; we don't know about classes in C */
#endif
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
struct primconvert_context *primconvert;
struct u_suballocator query_allocator;
struct u_suballocator so_allocator;
struct hash_table *pso_cache;
struct hash_table *compute_pso_cache;
struct hash_table *root_signature_cache;
struct hash_table *cmd_signature_cache;
struct hash_table *gs_variant_cache;
struct hash_table *tcs_variant_cache;
struct hash_table *compute_transform_cache;
struct pipe_constant_buffer cbufs[MESA_SHADER_STAGES][PIPE_MAX_CONSTANT_BUFFERS];
struct d3d12_surface *fb_cbufs[PIPE_MAX_COLOR_BUFS];
struct d3d12_surface *fb_zsbuf;
struct pipe_framebuffer_state fb;
struct pipe_vertex_buffer vbs[PIPE_MAX_ATTRIBS];
D3D12_VERTEX_BUFFER_VIEW vbvs[PIPE_MAX_ATTRIBS];
unsigned num_vbs;
float flip_y;
bool need_zero_one_depth_range;
enum mesa_prim initial_api_prim;
struct pipe_viewport_state viewport_states[PIPE_MAX_VIEWPORTS];
D3D12_VIEWPORT viewports[PIPE_MAX_VIEWPORTS];
unsigned num_viewports;
struct pipe_scissor_state scissor_states[PIPE_MAX_VIEWPORTS];
D3D12_RECT scissors[PIPE_MAX_VIEWPORTS];
float blend_factor[4];
struct pipe_stencil_ref stencil_ref;
struct pipe_sampler_view *sampler_views[MESA_SHADER_STAGES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
unsigned num_sampler_views[MESA_SHADER_STAGES];
unsigned has_int_samplers;
struct pipe_shader_buffer ssbo_views[MESA_SHADER_STAGES][PIPE_MAX_SHADER_BUFFERS];
unsigned num_ssbo_views[MESA_SHADER_STAGES];
struct pipe_image_view image_views[MESA_SHADER_STAGES][PIPE_MAX_SHADER_IMAGES];
enum pipe_format image_view_emulation_formats[MESA_SHADER_STAGES][PIPE_MAX_SHADER_IMAGES];
unsigned num_image_views[MESA_SHADER_STAGES];
struct d3d12_sampler_state *samplers[MESA_SHADER_STAGES][PIPE_MAX_SAMPLERS];
unsigned num_samplers[MESA_SHADER_STAGES];
D3D12_INDEX_BUFFER_VIEW ibv;
dxil_wrap_sampler_state tex_wrap_states[MESA_SHADER_STAGES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
dxil_wrap_sampler_state tex_wrap_states_shader_key[PIPE_MAX_SHADER_SAMPLER_VIEWS];
dxil_texture_swizzle_state tex_swizzle_state[MESA_SHADER_STAGES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
enum compare_func tex_compare_func[MESA_SHADER_STAGES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
struct {
bool enabled;
uint32_t pattern[32];
struct pipe_resource *texture;
struct pipe_sampler_view *sampler_view;
struct d3d12_sampler_state *sampler_cso;
} pstipple;
struct pipe_stream_output_target *so_targets[PIPE_MAX_SO_BUFFERS];
D3D12_STREAM_OUTPUT_BUFFER_VIEW so_buffer_views[PIPE_MAX_SO_BUFFERS];
struct pipe_stream_output_target *fake_so_targets[PIPE_MAX_SO_BUFFERS];
D3D12_STREAM_OUTPUT_BUFFER_VIEW fake_so_buffer_views[PIPE_MAX_SO_BUFFERS];
unsigned fake_so_buffer_factor;
uint8_t patch_vertices;
float default_outer_tess_factor[4];
float default_inner_tess_factor[2];
struct d3d12_shader_selector *gfx_stages[D3D12_GFX_SHADER_STAGES];
struct d3d12_shader_selector *compute_state;
bool has_flat_varyings;
bool missing_dual_src_outputs;
bool manual_depth_range;
struct d3d12_gfx_pipeline_state gfx_pipeline_state;
struct d3d12_compute_pipeline_state compute_pipeline_state;
unsigned shader_dirty[MESA_SHADER_STAGES];
unsigned state_dirty;
unsigned cmdlist_dirty;
ID3D12PipelineState *current_gfx_pso;
ID3D12PipelineState *current_compute_pso;
uint16_t reverse_depth_range;
struct list_head active_queries;
struct d3d12_descriptor_pool *sampler_pool;
struct d3d12_descriptor_handle null_sampler;
PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignature;
#ifndef _GAMING_XBOX
ID3D12DeviceConfiguration *dev_config;
#endif
#ifdef _WIN32
struct dxil_validator *dxil_validator;
#endif
struct d3d12_resource *current_predication;
bool predication_condition;
bool queries_suspended;
uint32_t transform_state_vars[8];
struct pipe_query *timestamp_query;
/* used by d3d12_blit.cpp */
void *stencil_resolve_vs, *stencil_resolve_fs, *stencil_resolve_fs_no_flip, *sampler_state;
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
struct d3d12_context_queue_priority_manager* priority_manager; // Object passed and managed by frontend
mtx_t priority_manager_lock; // Mutex to protect access to priority_manager
uint32_t max_video_encoding_async_depth = 0u;
};
static inline struct d3d12_context *
d3d12_context(struct pipe_context *context)
{
return (struct d3d12_context *)context;
}
static inline struct d3d12_batch *
d3d12_current_batch(struct d3d12_context *ctx)
{
assert(ctx->current_batch_idx < ARRAY_SIZE(ctx->batches));
return ctx->batches + ctx->current_batch_idx;
}
#define d3d12_foreach_submitted_batch(ctx, batch) \
unsigned oldest = (ctx->current_batch_idx + 1) % ARRAY_SIZE(ctx->batches); \
while (ctx->batches[oldest].fence == NULL && oldest != ctx->current_batch_idx) \
oldest = (oldest + 1) % ARRAY_SIZE(ctx->batches); \
struct d3d12_batch *batch = &ctx->batches[oldest]; \
for (; oldest != ctx->current_batch_idx; \
oldest = (oldest + 1) % ARRAY_SIZE(ctx->batches), \
batch = &ctx->batches[oldest])
struct pipe_context *
d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags);
int
d3d12_context_set_queue_priority_manager(struct pipe_context *ctx, struct d3d12_context_queue_priority_manager *priority_manager);
#ifdef HAVE_GALLIUM_D3D12_VIDEO
int
d3d12_video_encoder_set_max_async_queue_depth(struct pipe_context *ctx, uint32_t max_async_depth);
int
d3d12_video_encoder_get_last_slice_completion_fence(struct pipe_video_codec *codec,
void *feedback,
pipe_fence_handle **last_slice_completion_fence);
#endif // HAVE_GALLIUM_D3D12_VIDEO
bool
d3d12_enable_fake_so_buffers(struct d3d12_context *ctx, unsigned factor);
bool
d3d12_disable_fake_so_buffers(struct d3d12_context *ctx);
bool
d3d12_flush_cmdlist(struct d3d12_context *ctx);
void
d3d12_flush_cmdlist_and_wait(struct d3d12_context *ctx);
enum d3d12_transition_flags {
D3D12_TRANSITION_FLAG_NONE = 0,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS = 1,
D3D12_TRANSITION_FLAG_ACCUMULATE_STATE = 2,
D3D12_TRANSITION_FLAG_PENDING_MEMORY_BARRIER = 4,
};
void
d3d12_transition_resource_state(struct d3d12_context* ctx,
struct d3d12_resource* res,
D3D12_RESOURCE_STATES state,
d3d12_transition_flags flags);
void
d3d12_transition_subresources_state(struct d3d12_context *ctx,
struct d3d12_resource *res,
unsigned start_level, unsigned num_levels,
unsigned start_layer, unsigned num_layers,
unsigned start_plane, unsigned num_planes,
D3D12_RESOURCE_STATES state,
d3d12_transition_flags flags);
void
d3d12_apply_resource_states(struct d3d12_context* ctx, bool is_implicit_dispatch);
void
d3d12_draw_vbo(struct pipe_context *pctx,
const struct pipe_draw_info *dinfo,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
const struct pipe_draw_start_count_bias *draws,
unsigned num_draws);
void
d3d12_launch_grid(struct pipe_context *pctx,
const struct pipe_grid_info *info);
void
d3d12_blit(struct pipe_context *pctx,
const struct pipe_blit_info *info);
void
d3d12_context_query_init(struct pipe_context *pctx);
bool
d3d12_need_zero_one_depth_range(struct d3d12_context *ctx);
void
d3d12_init_sampler_view_descriptor(struct d3d12_sampler_view *sampler_view);
void
d3d12_invalidate_context_bindings(struct d3d12_context *ctx, struct d3d12_resource *res);
void
d3d12_rebind_buffer(struct d3d12_context *ctx, struct d3d12_resource *res);
void
d3d12_init_null_sampler(struct d3d12_context *ctx);
bool
d3d12_init_polygon_stipple(struct pipe_context *pctx);
void
d3d12_init_graphics_context_functions(struct d3d12_context *ctx);
#ifdef HAVE_GALLIUM_D3D12_VIDEO
struct pipe_video_codec* d3d12_video_create_codec( struct pipe_context *context,
const struct pipe_video_codec *t);
#endif
#endif
@@ -0,0 +1,689 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_blit.h"
#include "d3d12_cmd_signature.h"
#include "d3d12_context.h"
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
#include "d3d12_compiler.h"
#include "d3d12_compute_transforms.h"
#include "nir_to_dxil.h"
#ifdef _WIN32
#include "dxil_validator.h"
#endif
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
#include "d3d12_debug.h"
#include "d3d12_fence.h"
#include "d3d12_format.h"
#include "d3d12_query.h"
#include "d3d12_resource.h"
#include "d3d12_root_signature.h"
#include "d3d12_screen.h"
#include "d3d12_surface.h"
#ifdef HAVE_GALLIUM_D3D12_VIDEO
#include "d3d12_video_dec.h"
#include "d3d12_video_enc.h"
#include "d3d12_video_proc.h"
#include "d3d12_video_buffer.h"
#endif
#include "indices/u_primconvert.h"
#include "util/u_atomic.h"
#include "util/u_blitter.h"
#include "util/set.h"
#include "util/u_dual_blend.h"
#include "util/u_framebuffer.h"
#include "util/u_helpers.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_upload_mgr.h"
#include "util/u_pstipple.h"
#include "util/u_sample_positions.h"
#include "util/u_dl.h"
#include <dxguids/dxguids.h>
#include <string.h>
#include "d3d12_interop_public.h"
#ifndef _GAMING_XBOX
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
#endif
static void
d3d12_context_destroy(struct pipe_context *pctx)
{
struct d3d12_context *ctx = d3d12_context(pctx);
if (ctx->priority_manager)
{
struct d3d12_screen *screen = d3d12_screen(pctx->screen);
if (ctx->priority_manager->unregister_work_queue(ctx->priority_manager, screen->cmdqueue) != 0)
{
debug_printf("D3D12: Failed to unregister command queue with frontend priority manager\n");
assert(false);
}
mtx_destroy(&ctx->priority_manager_lock);
}
struct d3d12_screen *screen = d3d12_screen(pctx->screen);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if ((screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) && !(ctx->flags & PIPE_CONTEXT_MEDIA_ONLY)) {
util_blitter_destroy(ctx->blitter); // Must be called before d3d12_destroy_batch
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
// Batch must be destroyed before the rest of the state objects below
d3d12_end_batch(ctx, d3d12_current_batch(ctx));
for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i)
d3d12_destroy_batch(ctx, &ctx->batches[i]);
ctx->cmdlist->Release();
if (ctx->cmdlist2)
ctx->cmdlist2->Release();
if (ctx->cmdlist8)
ctx->cmdlist8->Release();
mtx_lock(&screen->submit_mutex);
list_del(&ctx->context_list_entry);
if (ctx->id != D3D12_CONTEXT_NO_ID) {
unsigned context_bit = 1u << ctx->id;
set_foreach(ctx->local_state_bos, entry) {
struct d3d12_bo *bo = (struct d3d12_bo *)entry->key;
if (bo->local_context_state_mask & context_bit) {
d3d12_destroy_context_state_table_entry(&bo->local_context_states[ctx->id]);
bo->local_context_state_mask &= ~context_bit;
}
}
_mesa_set_clear(ctx->local_state_bos, nullptr);
screen->context_id_list[screen->context_id_count++] = ctx->id;
}
mtx_unlock(&screen->submit_mutex);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if ((screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) && !(ctx->flags & PIPE_CONTEXT_MEDIA_ONLY)) {
#ifdef _WIN32
dxil_destroy_validator(ctx->dxil_validator);
#endif // _WIN32
#ifndef _GAMING_XBOX
if (ctx->dev_config)
ctx->dev_config->Release();
#endif // _GAMING_XBOX
if (ctx->timestamp_query)
pctx->destroy_query(pctx, ctx->timestamp_query);
util_unreference_framebuffer_state(&ctx->fb);
d3d12_compute_pipeline_state_cache_destroy(ctx);
d3d12_root_signature_cache_destroy(ctx);
d3d12_cmd_signature_cache_destroy(ctx);
d3d12_compute_transform_cache_destroy(ctx);
d3d12_descriptor_pool_free(ctx->sampler_pool);
d3d12_gs_variant_cache_destroy(ctx);
d3d12_tcs_variant_cache_destroy(ctx);
d3d12_gfx_pipeline_state_cache_destroy(ctx);
util_primconvert_destroy(ctx->primconvert);
pipe_resource_reference(&ctx->pstipple.texture, nullptr);
pipe_sampler_view_reference(&ctx->pstipple.sampler_view, nullptr);
util_dynarray_fini(&ctx->recently_destroyed_bos);
FREE(ctx->pstipple.sampler_cso);
if (pctx->stream_uploader)
u_upload_destroy(pctx->stream_uploader);
if (pctx->const_uploader)
u_upload_destroy(pctx->const_uploader);
if (!ctx->queries_disabled) {
u_suballocator_destroy(&ctx->query_allocator);
}
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
slab_destroy_child(&ctx->transfer_pool);
slab_destroy_child(&ctx->transfer_pool_unsync);
d3d12_context_state_table_destroy(ctx);
FREE(ctx);
}
bool
d3d12_flush_cmdlist(struct d3d12_context *ctx)
{
if (!ctx->has_commands)
return false;
d3d12_end_batch(ctx, d3d12_current_batch(ctx));
ctx->current_batch_idx++;
if (ctx->current_batch_idx == ARRAY_SIZE(ctx->batches))
ctx->current_batch_idx = 0;
d3d12_start_batch(ctx, d3d12_current_batch(ctx));
ctx->has_commands = false;
return true;
}
void
d3d12_flush_cmdlist_and_wait(struct d3d12_context *ctx)
{
struct d3d12_batch *batch = d3d12_current_batch(ctx);
d3d12_foreach_submitted_batch(ctx, old_batch)
d3d12_reset_batch(ctx, old_batch, OS_TIMEOUT_INFINITE);
if (d3d12_flush_cmdlist(ctx))
d3d12_reset_batch(ctx, batch, OS_TIMEOUT_INFINITE);
}
static void
d3d12_flush(struct pipe_context *pipe,
struct pipe_fence_handle **fence,
unsigned flags)
{
struct d3d12_context *ctx = d3d12_context(pipe);
struct d3d12_batch *batch = d3d12_current_batch(ctx);
bool flushed = d3d12_flush_cmdlist(ctx);
if (fence) {
if (flushed)
d3d12_fence_reference((struct d3d12_fence **)fence, batch->fence);
else
*fence = (pipe_fence_handle *)d3d12_create_fence(d3d12_screen(ctx->base.screen), false);
}
}
static void
d3d12_flush_resource(struct pipe_context *pctx,
struct pipe_resource *pres)
{
struct d3d12_context *ctx = d3d12_context(pctx);
struct d3d12_resource *res = d3d12_resource(pres);
d3d12_transition_resource_state(ctx, res,
D3D12_RESOURCE_STATE_COMMON,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_apply_resource_states(ctx, false);
d3d12_batch_reference_resource(d3d12_current_batch(ctx), res, true);
ctx->has_commands = true;
}
static void
d3d12_signal(struct pipe_context *pipe,
struct pipe_fence_handle *pfence,
uint64_t value)
{
struct d3d12_screen *screen = d3d12_screen(pipe->screen);
struct d3d12_fence *fence = d3d12_fence(pfence);
d3d12_flush_cmdlist(d3d12_context(pipe));
d3d12_fence_signal_impl(fence, screen->cmdqueue, value);
}
static void
d3d12_wait(struct pipe_context *pipe, struct pipe_fence_handle *pfence, uint64_t value)
{
struct d3d12_screen *screen = d3d12_screen(pipe->screen);
struct d3d12_fence *fence = d3d12_fence(pfence);
d3d12_flush_cmdlist(d3d12_context(pipe));
d3d12_fence_wait_impl(fence, screen->cmdqueue, value);
}
static void
d3d12_replace_buffer_storage(struct pipe_context *pctx,
struct pipe_resource *pdst,
struct pipe_resource *psrc,
unsigned minimum_num_rebinds,
uint32_t rebind_mask,
uint32_t delete_buffer_id)
{
struct d3d12_resource *dst = d3d12_resource(pdst);
struct d3d12_resource *src = d3d12_resource(psrc);
struct d3d12_bo *old_bo = dst->bo;
d3d12_bo_reference(src->bo);
dst->bo = src->bo;
p_atomic_inc(&dst->generation_id);
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
struct d3d12_context *ctx = d3d12_context(pctx);
if ((d3d12_screen(pctx->screen)->max_feature_level >= D3D_FEATURE_LEVEL_11_0)
&& !(ctx->flags & PIPE_CONTEXT_MEDIA_ONLY))
d3d12_rebind_buffer(ctx, dst);
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
d3d12_bo_unreference(old_bo);
}
static void
d3d12_memory_barrier(struct pipe_context *pctx, unsigned flags)
{
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
struct d3d12_context *ctx = d3d12_context(pctx);
if (flags & PIPE_BARRIER_VERTEX_BUFFER)
ctx->state_dirty |= D3D12_DIRTY_VERTEX_BUFFERS;
if (flags & PIPE_BARRIER_INDEX_BUFFER)
ctx->state_dirty |= D3D12_DIRTY_INDEX_BUFFER;
if (flags & PIPE_BARRIER_FRAMEBUFFER)
ctx->state_dirty |= D3D12_DIRTY_FRAMEBUFFER;
if (flags & PIPE_BARRIER_STREAMOUT_BUFFER)
ctx->state_dirty |= D3D12_DIRTY_STREAM_OUTPUT;
/* TODO:
* PIPE_BARRIER_INDIRECT_BUFFER
*/
for (unsigned i = 0; i < D3D12_GFX_SHADER_STAGES; ++i) {
if (flags & PIPE_BARRIER_CONSTANT_BUFFER)
ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_CONSTBUF;
if (flags & PIPE_BARRIER_TEXTURE)
ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SAMPLER_VIEWS;
if (flags & PIPE_BARRIER_SHADER_BUFFER)
ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SSBO;
if (flags & PIPE_BARRIER_IMAGE)
ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_IMAGE;
}
/* Indicate that UAVs shouldn't override transitions. Ignore barriers that are only
* for UAVs or other fixed-function state that doesn't need a draw to resolve.
*/
const unsigned ignored_barrier_flags =
PIPE_BARRIER_IMAGE |
PIPE_BARRIER_SHADER_BUFFER |
PIPE_BARRIER_UPDATE |
PIPE_BARRIER_MAPPED_BUFFER |
PIPE_BARRIER_QUERY_BUFFER;
d3d12_current_batch(ctx)->pending_memory_barrier = (flags & ~ignored_barrier_flags) != 0;
if (flags & (PIPE_BARRIER_IMAGE | PIPE_BARRIER_SHADER_BUFFER)) {
D3D12_RESOURCE_BARRIER uavBarrier;
uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
uavBarrier.UAV.pResource = nullptr;
ctx->cmdlist->ResourceBarrier(1, &uavBarrier);
ctx->has_commands = true;
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
}
static void
d3d12_texture_barrier(struct pipe_context *pctx, unsigned flags)
{
struct d3d12_context *ctx = d3d12_context(pctx);
/* D3D doesn't really have an equivalent in the legacy barrier model. When using enhanced barriers,
* this could be a more specific global barrier. But for now, just flush the world with an aliasing barrier. */
D3D12_RESOURCE_BARRIER aliasingBarrier;
aliasingBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
aliasingBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
aliasingBarrier.Aliasing.pResourceBefore = nullptr;
aliasingBarrier.Aliasing.pResourceAfter = nullptr;
ctx->cmdlist->ResourceBarrier(1, &aliasingBarrier);
ctx->has_commands = true;
}
static enum pipe_reset_status
d3d12_get_reset_status(struct pipe_context *pctx)
{
struct d3d12_screen *screen = d3d12_screen(pctx->screen);
HRESULT hr = screen->dev->GetDeviceRemovedReason();
switch (hr) {
case DXGI_ERROR_DEVICE_HUNG:
case DXGI_ERROR_INVALID_CALL:
return PIPE_GUILTY_CONTEXT_RESET;
case DXGI_ERROR_DEVICE_RESET:
return PIPE_INNOCENT_CONTEXT_RESET;
default:
return SUCCEEDED(hr) ? PIPE_NO_RESET : PIPE_UNKNOWN_CONTEXT_RESET;
}
}
#ifdef HAVE_GALLIUM_D3D12_VIDEO
struct pipe_video_codec*
d3d12_video_create_codec(struct pipe_context *context,
const struct pipe_video_codec *templat)
{
if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
return d3d12_video_encoder_create_encoder(context, templat);
} else if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
return d3d12_video_create_decoder(context, templat);
} else if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
return d3d12_video_processor_create(context, templat);
} else {
debug_printf("D3D12: Unsupported video codec entrypoint %d\n", templat->entrypoint);
return nullptr;
}
}
#endif
int
d3d12_context_set_queue_priority(struct d3d12_context_queue_priority_manager* manager,
ID3D12CommandQueue *d3d12_queue,
const uint32_t* global_priority,
const uint32_t* local_priority)
{
if (!global_priority || !local_priority)
return -1;
struct d3d12_context* ctx12 = d3d12_context(manager->context);
mtx_lock(&ctx12->priority_manager_lock);
{
// Set the queue priority
ComPtr<ID3D12CommandQueue1> prio_iface;
if(FAILED(d3d12_queue->QueryInterface(IID_PPV_ARGS(&prio_iface))))
{
mtx_unlock(&ctx12->priority_manager_lock);
return -1;
}
D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY global_priority_val = static_cast<D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY>(*global_priority);
if(FAILED(prio_iface->SetGlobalPriority(global_priority_val)))
{
mtx_unlock(&ctx12->priority_manager_lock);
return -1;
}
D3D12_COMMAND_QUEUE_PROCESS_PRIORITY local_priority_val = static_cast<D3D12_COMMAND_QUEUE_PROCESS_PRIORITY>(*local_priority);
if(FAILED(prio_iface->SetProcessPriority(local_priority_val)))
{
mtx_unlock(&ctx12->priority_manager_lock);
return -1;
}
}
mtx_unlock(&ctx12->priority_manager_lock);
return 0;
}
int
d3d12_context_get_queue_priority(struct d3d12_context_queue_priority_manager* manager,
ID3D12CommandQueue *d3d12_queue,
uint32_t *global_priority,
uint32_t *local_priority)
{
struct d3d12_context* ctx12 = d3d12_context(manager->context);
mtx_lock(&ctx12->priority_manager_lock);
{
ComPtr<ID3D12CommandQueue1> prio_iface;
if (FAILED(d3d12_queue->QueryInterface(IID_PPV_ARGS(&prio_iface))))
{
mtx_unlock(&ctx12->priority_manager_lock);
return -1;
}
if (global_priority)
{
D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY global_priority_val = {};
if (FAILED(prio_iface->GetGlobalPriority(&global_priority_val)))
{
mtx_unlock(&ctx12->priority_manager_lock);
return -1;
}
*global_priority = static_cast<uint32_t>(global_priority_val);
}
if (local_priority)
{
D3D12_COMMAND_QUEUE_PROCESS_PRIORITY local_priority_val = {};
if (FAILED(prio_iface->GetProcessPriority(&local_priority_val)))
{
mtx_unlock(&ctx12->priority_manager_lock);
return -1;
}
*local_priority = static_cast<uint32_t>(local_priority_val);
}
}
mtx_unlock(&ctx12->priority_manager_lock);
return 0;
}
int
d3d12_context_set_queue_priority_manager(struct pipe_context *ctx, struct d3d12_context_queue_priority_manager *priority_manager)
{
if (ctx && priority_manager)
{
struct d3d12_context *d3d12_ctx = d3d12_context(ctx);
d3d12_ctx->priority_manager = (struct d3d12_context_queue_priority_manager*) priority_manager;
// Validate that the frontend has set all required function pointers
assert ( d3d12_ctx->priority_manager->register_work_queue );
assert ( d3d12_ctx->priority_manager->unregister_work_queue );
// Initialize the priority manager lock
if (thrd_success != mtx_init(&d3d12_ctx->priority_manager_lock, mtx_plain))
{
debug_printf("D3D12: Failed to initialize context priority manager lock\n");
return 1;
}
//
// Fill the function pointers for the context queue priority manager that the frontend expects
//
d3d12_ctx->priority_manager->context = ctx;
d3d12_ctx->priority_manager->set_queue_priority = d3d12_context_set_queue_priority;
d3d12_ctx->priority_manager->get_queue_priority = d3d12_context_get_queue_priority;
// Register the context's command queue with the frontend's priority manager
struct d3d12_screen *screen = d3d12_screen(ctx->screen);
if (d3d12_ctx->priority_manager->register_work_queue(d3d12_ctx->priority_manager, screen->cmdqueue) != 0)
{
debug_printf("D3D12: Failed to register command queue with frontend priority manager\n");
return 1;
}
}
return 0;
}
#ifdef HAVE_GALLIUM_D3D12_VIDEO
int
d3d12_video_encoder_set_max_async_queue_depth(struct pipe_context *ctx, uint32_t max_async_depth)
{
if (max_async_depth > 8) {
debug_printf("d3d12_video_encoder_set_max_async_queue_depth: max_async_depth must be between 1 and 8\n");
return -1;
}
struct d3d12_context *d3d12_ctx = d3d12_context(ctx);
d3d12_ctx->max_video_encoding_async_depth = max_async_depth;
return 0;
}
#endif // HAVE_GALLIUM_D3D12_VIDEO
struct pipe_context *
d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
{
struct d3d12_screen *screen = d3d12_screen(pscreen);
if (FAILED(screen->dev->GetDeviceRemovedReason())) {
/* Attempt recovery, but this may fail */
screen->deinit(screen);
if (!screen->init(screen)) {
debug_printf("D3D12: failed to reset screen\n");
return nullptr;
}
}
if ((screen->max_feature_level < D3D_FEATURE_LEVEL_11_0) &&
!(flags & PIPE_CONTEXT_MEDIA_ONLY))
{
debug_printf("D3D12: Underlying screen maximum supported feature level is lower than D3D_FEATURE_LEVEL_11_0. The caller to context_create must pass PIPE_CONTEXT_MEDIA_ONLY in flags.\n");
return NULL;
}
#ifndef HAVE_GALLIUM_D3D12_VIDEO
if (flags & PIPE_CONTEXT_MEDIA_ONLY)
{
debug_printf("D3D12: context_create passed PIPE_CONTEXT_MEDIA_ONLY in flags but no media support found.\n");
return NULL;
}
#endif // ifndef HAVE_GALLIUM_D3D12_VIDEO
struct d3d12_context *ctx = CALLOC_STRUCT(d3d12_context);
if (!ctx)
return NULL;
ctx->max_video_encoding_async_depth = static_cast<uint32_t>(debug_get_num_option("D3D12_VIDEO_ENC_ASYNC_DEPTH", 8));
ctx->base.screen = pscreen;
ctx->base.priv = priv;
ctx->base.destroy = d3d12_context_destroy;
ctx->base.flush = d3d12_flush;
ctx->base.flush_resource = d3d12_flush_resource;
ctx->base.fence_server_signal = d3d12_signal;
ctx->base.fence_server_sync = d3d12_wait;
ctx->base.memory_barrier = d3d12_memory_barrier;
ctx->base.texture_barrier = d3d12_texture_barrier;
ctx->base.get_device_reset_status = d3d12_get_reset_status;
ctx->flags = flags;
d3d12_context_resource_init(&ctx->base);
d3d12_context_copy_init(&ctx->base);
#ifdef HAVE_GALLIUM_D3D12_VIDEO
ctx->base.create_video_codec = d3d12_video_create_codec;
ctx->base.create_video_buffer = d3d12_video_buffer_create;
ctx->base.video_buffer_from_handle = d3d12_video_buffer_from_handle;
#endif
slab_create_child(&ctx->transfer_pool, &d3d12_screen(pscreen)->transfer_pool);
slab_create_child(&ctx->transfer_pool_unsync, &d3d12_screen(pscreen)->transfer_pool);
d3d12_context_state_table_init(ctx);
ctx->queries_disabled = true; // Disabled by default, re-enable if supported FL below
#ifdef HAVE_GALLIUM_D3D12_GRAPHICS
if ((screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) && !(flags & PIPE_CONTEXT_MEDIA_ONLY)) {
#ifndef _GAMING_XBOX
(void)screen->dev->QueryInterface(&ctx->dev_config);
#endif
d3d12_context_blit_init(&ctx->base);
u_suballocator_init(&ctx->so_allocator, &ctx->base, 4096, 0,
PIPE_USAGE_DEFAULT,
0, false);
ctx->has_flat_varyings = false;
ctx->missing_dual_src_outputs = false;
ctx->manual_depth_range = false;
d3d12_compute_pipeline_state_cache_init(ctx);
d3d12_root_signature_cache_init(ctx);
d3d12_cmd_signature_cache_init(ctx);
d3d12_compute_transform_cache_init(ctx);
ctx->D3D12SerializeVersionedRootSignature =
(PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)util_dl_get_proc_address(screen->d3d12_mod, "D3D12SerializeVersionedRootSignature");
ctx->base.stream_uploader = u_upload_create_default(&ctx->base);
ctx->base.const_uploader = u_upload_create_default(&ctx->base);
ctx->base.get_sample_position = u_default_get_sample_position;
ctx->base.get_sample_position = u_default_get_sample_position;
d3d12_init_graphics_context_functions(ctx);
ctx->gfx_pipeline_state.sample_mask = ~0;
d3d12_context_query_init(&ctx->base);
ctx->queries_disabled = false;
struct primconvert_config cfg = {};
cfg.primtypes_mask = 1 << MESA_PRIM_POINTS |
1 << MESA_PRIM_LINES |
1 << MESA_PRIM_LINE_STRIP |
1 << MESA_PRIM_TRIANGLES |
1 << MESA_PRIM_TRIANGLE_STRIP;
cfg.restart_primtypes_mask = cfg.primtypes_mask;
cfg.fixed_prim_restart = true;
ctx->primconvert = util_primconvert_create_config(&ctx->base, &cfg);
if (!ctx->primconvert) {
debug_printf("D3D12: failed to create primconvert\n");
return NULL;
}
d3d12_gfx_pipeline_state_cache_init(ctx);
d3d12_gs_variant_cache_init(ctx);
d3d12_tcs_variant_cache_init(ctx);
ctx->sampler_pool = d3d12_descriptor_pool_new(screen,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
64);
if (!ctx->sampler_pool) {
FREE(ctx);
return NULL;
}
d3d12_init_null_sampler(ctx);
ctx->blitter = util_blitter_create(&ctx->base);
if (!ctx->blitter)
return NULL;
if (!d3d12_init_polygon_stipple(&ctx->base)) {
debug_printf("D3D12: failed to initialize polygon stipple resources\n");
FREE(ctx);
return NULL;
}
#ifdef _WIN32
if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) ||
(d3d12_debug & D3D12_DEBUG_DISASS))
ctx->dxil_validator = dxil_create_validator(NULL);
#endif
}
#endif // HAVE_GALLIUM_D3D12_GRAPHICS
ctx->submit_id = (uint64_t)p_atomic_add_return(&screen->ctx_count, 1) << 32ull;
for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i) {
if (!d3d12_init_batch(ctx, &ctx->batches[i])) {
FREE(ctx);
return NULL;
}
}
d3d12_start_batch(ctx, &ctx->batches[0]);
mtx_lock(&screen->submit_mutex);
list_addtail(&ctx->context_list_entry, &screen->context_list);
if (screen->context_id_count > 0)
ctx->id = screen->context_id_list[--screen->context_id_count];
else
ctx->id = D3D12_CONTEXT_NO_ID;
mtx_unlock(&screen->submit_mutex);
for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i) {
ctx->batches[i].ctx_id = ctx->id;
ctx->batches[i].ctx_index = i;
}
if (flags & PIPE_CONTEXT_PREFER_THREADED) {
struct pipe_context *ret = threaded_context_create(&ctx->base,
&screen->transfer_pool,
d3d12_replace_buffer_storage,
NULL,
&ctx->threaded_context);
if (ctx->threaded_context) {
ctx->threaded_context->bytes_replaced_limit = 1024 * 1024 * 1024; /* 1GiB */
threaded_context_init_bytes_mapped_limit(ctx->threaded_context, 4);
}
return ret;
}
return &ctx->base;
}
File diff suppressed because it is too large. Load diff
+363
View File
@@ -0,0 +1,363 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_context.h"
#include "d3d12_debug.h"
#include "d3d12_format.h"
#include "d3d12_query.h"
#include "d3d12_resource.h"
#include "d3d12_screen.h"
#include "util/u_blitter.h"
#include "util/format/u_format.h"
static void
copy_buffer_region_no_barriers(struct d3d12_context *ctx,
struct d3d12_resource *dst,
uint64_t dst_offset,
struct d3d12_resource *src,
uint64_t src_offset,
uint64_t size)
{
uint64_t dst_off, src_off;
ID3D12Resource *dst_buf = d3d12_resource_underlying(dst, &dst_off);
ID3D12Resource *src_buf = d3d12_resource_underlying(src, &src_off);
ctx->cmdlist->CopyBufferRegion(dst_buf, dst_offset + dst_off,
src_buf, src_offset + src_off,
size);
ctx->has_commands = true;
}
inline static unsigned
get_subresource_id(enum pipe_texture_target target, unsigned subres, unsigned stride,
unsigned z, unsigned *updated_z, unsigned array_size, unsigned plane_slice)
{
if (d3d12_subresource_id_uses_layer(target)) {
subres += stride * z;
if (updated_z)
*updated_z = 0;
}
return subres + plane_slice * array_size * stride;
}
static void
copy_subregion_no_barriers(struct d3d12_context *ctx,
struct d3d12_resource *dst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct d3d12_resource *src,
unsigned src_level,
const struct pipe_box *psrc_box,
unsigned mask)
{
UNUSED struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
D3D12_TEXTURE_COPY_LOCATION src_loc, dst_loc;
unsigned src_z = psrc_box->z;
int src_subres_stride = src->base.b.last_level + 1;
int dst_subres_stride = dst->base.b.last_level + 1;
int src_array_size = src->base.b.array_size;
int dst_array_size = dst->base.b.array_size;
int stencil_src_res_offset = 1;
int stencil_dst_res_offset = 1;
int src_nres = 1;
int dst_nres = 1;
if (dst->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
dst->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
stencil_dst_res_offset = dst_subres_stride * dst_array_size;
src_nres = 2;
}
if (src->base.b.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
src->base.b.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
dst->base.b.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
stencil_src_res_offset = src_subres_stride * src_array_size;
dst_nres = 2;
}
static_assert(PIPE_MASK_S == 0x20 && PIPE_MASK_Z == 0x10, "unexpected ZS format mask");
int nsubres = MIN2(src_nres, dst_nres);
unsigned subresource_copy_mask = nsubres > 1 ? mask >> 4 : 1;
for (int subres = 0; subres < nsubres; ++subres) {
if (!(subresource_copy_mask & (1 << subres)))
continue;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src_loc.SubresourceIndex = get_subresource_id(src->base.b.target, src_level, src_subres_stride, src_z, &src_z, src_array_size, src->plane_slice) +
subres * stencil_src_res_offset;
src_loc.pResource = d3d12_resource_resource(src);
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = get_subresource_id(dst->base.b.target, dst_level, dst_subres_stride, dstz, &dstz, dst_array_size, dst->plane_slice) +
subres * stencil_dst_res_offset;
dst_loc.pResource = d3d12_resource_resource(dst);
if (psrc_box->x == 0 && psrc_box->y == 0 && psrc_box->z == 0 &&
psrc_box->width == (int)u_minify(src->base.b.width0, src_level) &&
psrc_box->height == (int)u_minify(src->base.b.height0, src_level) &&
psrc_box->depth == (int)u_minify(src->base.b.depth0, src_level)) {
assert((dstx == 0 && dsty == 0 && dstz == 0) ||
screen->opts2.ProgrammableSamplePositionsTier !=
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
(!util_format_is_depth_or_stencil(dst->base.b.format) &&
!util_format_is_depth_or_stencil(src->base.b.format) &&
dst->base.b.nr_samples == src->base.b.nr_samples));
ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
&src_loc, NULL);
ctx->has_commands = true;
} else {
D3D12_BOX src_box;
src_box.left = psrc_box->x;
src_box.right = MIN2(psrc_box->x + psrc_box->width, (int)u_minify(src->base.b.width0, src_level));
src_box.top = psrc_box->y;
src_box.bottom = MIN2(psrc_box->y + psrc_box->height, (int)u_minify(src->base.b.height0, src_level));
src_box.front = src_z;
src_box.back = src_z + psrc_box->depth;
assert((screen->opts2.ProgrammableSamplePositionsTier !=
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||
(!util_format_is_depth_or_stencil(dst->base.b.format) &&
!util_format_is_depth_or_stencil(src->base.b.format))) &&
dst->base.b.nr_samples == src->base.b.nr_samples);
ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,
&src_loc, &src_box);
ctx->has_commands = true;
}
}
}
static void
copy_resource_y_flipped_no_barriers(struct d3d12_context *ctx,
struct d3d12_resource *dst,
unsigned dst_level,
const struct pipe_box *pdst_box,
struct d3d12_resource *src,
unsigned src_level,
const struct pipe_box *psrc_box,
unsigned mask)
{
if (D3D12_DEBUG_BLIT & d3d12_debug) {
debug_printf("D3D12 BLIT as COPY: from %s@%d %dx%dx%d + %dx%dx%d\n",
util_format_name(src->base.b.format), src_level,
psrc_box->x, psrc_box->y, psrc_box->z,
psrc_box->width, psrc_box->height, psrc_box->depth);
debug_printf(" to %s@%d %dx%dx%d\n",
util_format_name(dst->base.b.format), dst_level,
pdst_box->x, pdst_box->y, pdst_box->z);
}
struct pipe_box src_box = *psrc_box;
int src_inc = psrc_box->height > 0 ? 1 : -1;
int dst_inc = pdst_box->height > 0 ? 1 : -1;
src_box.height = 1;
int rows_to_copy = abs(psrc_box->height);
if (psrc_box->height < 0)
--src_box.y;
for (int y = 0, dest_y = pdst_box->y; y < rows_to_copy;
++y, src_box.y += src_inc, dest_y += dst_inc) {
copy_subregion_no_barriers(ctx, dst, dst_level,
pdst_box->x, dest_y, pdst_box->z,
src, src_level, &src_box, mask);
}
}
void
d3d12_direct_copy(struct d3d12_context *ctx,
struct d3d12_resource *dst,
unsigned dst_level,
const struct pipe_box *pdst_box,
struct d3d12_resource *src,
unsigned src_level,
const struct pipe_box *psrc_box,
unsigned mask)
{
struct d3d12_batch *batch = d3d12_current_batch(ctx);
unsigned src_subres = get_subresource_id(src->base.b.target, src_level, src->base.b.last_level + 1,
psrc_box->z, nullptr, src->base.b.array_size, src->plane_slice);
unsigned dst_subres = get_subresource_id(dst->base.b.target, dst_level, dst->base.b.last_level + 1,
pdst_box->z, nullptr, dst->base.b.array_size, dst->plane_slice);
if (D3D12_DEBUG_BLIT & d3d12_debug)
debug_printf("BLIT: Direct copy from subres %d to subres %d\n",
src_subres, dst_subres);
d3d12_transition_subresources_state(ctx, src, src_subres, 1, 0, 1,
d3d12_get_format_start_plane(src->base.b.format),
d3d12_get_format_num_planes(src->base.b.format),
D3D12_RESOURCE_STATE_COPY_SOURCE,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_transition_subresources_state(ctx, dst, dst_subres, 1, 0, 1,
d3d12_get_format_start_plane(dst->base.b.format),
d3d12_get_format_num_planes(dst->base.b.format),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
d3d12_apply_resource_states(ctx, false);
d3d12_batch_reference_resource(batch, src, false);
d3d12_batch_reference_resource(batch, dst, true);
if (src->base.b.target == PIPE_BUFFER) {
copy_buffer_region_no_barriers(ctx, dst, pdst_box->x,
src, psrc_box->x, psrc_box->width);
} else if (psrc_box->height == pdst_box->height) {
/* No flipping, we can forward this directly to resource_copy_region */
copy_subregion_no_barriers(ctx, dst, dst_level,
pdst_box->x, pdst_box->y, pdst_box->z,
src, src_level, psrc_box, mask);
} else {
assert(psrc_box->height == -pdst_box->height);
copy_resource_y_flipped_no_barriers(ctx, dst, dst_level, pdst_box,
src, src_level, psrc_box, mask);
}
}
struct pipe_resource *
create_staging_resource(struct d3d12_context *ctx,
struct d3d12_resource *src,
unsigned src_level,
const struct pipe_box *src_box,
struct pipe_box *dst_box,
unsigned mask)
{
struct pipe_resource templ = {};
struct pipe_resource *staging_res;
struct pipe_box copy_src;
u_box_3d(MIN2(src_box->x, src_box->x + src_box->width),
MIN2(src_box->y, src_box->y + src_box->height),
MIN2(src_box->z, src_box->z + src_box->depth),
abs(src_box->width), abs(src_box->height), abs(src_box->depth),
&copy_src);
templ.format = src->base.b.format;
templ.width0 = copy_src.width;
templ.height0 = static_cast<uint16_t>(copy_src.height);
templ.depth0 = copy_src.depth;
templ.array_size = 1;
templ.nr_samples = src->base.b.nr_samples;
templ.nr_storage_samples = src->base.b.nr_storage_samples;
templ.usage = PIPE_USAGE_STAGING;
templ.bind = util_format_is_depth_or_stencil(templ.format) ? PIPE_BIND_DEPTH_STENCIL :
util_format_is_compressed(templ.format) ? 0 : PIPE_BIND_RENDER_TARGET;
templ.target = src->base.b.target;
staging_res = ctx->base.screen->resource_create(ctx->base.screen, &templ);
dst_box->x = 0;
dst_box->y = 0;
dst_box->z = 0;
dst_box->width = copy_src.width;
dst_box->height = copy_src.height;
dst_box->depth = copy_src.depth;
d3d12_direct_copy(ctx, d3d12_resource(staging_res), 0, dst_box,
src, src_level, &copy_src, mask);
if (src_box->width < 0) {
dst_box->x = dst_box->width;
dst_box->width = src_box->width;
}
if (src_box->height < 0) {
dst_box->y = dst_box->height;
dst_box->height = src_box->height;
}
if (src_box->depth < 0) {
dst_box->z = dst_box->depth;
dst_box->depth = src_box->depth;
}
return staging_res;
}
static void
d3d12_resource_copy_region(struct pipe_context *pctx,
struct pipe_resource *pdst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct pipe_resource *psrc,
unsigned src_level,
const struct pipe_box *psrc_box)
{
struct d3d12_context *ctx = d3d12_context(pctx);
struct d3d12_resource *dst = d3d12_resource(pdst);
struct d3d12_resource *src = d3d12_resource(psrc);
struct pipe_resource *staging_res = NULL;
const struct pipe_box *src_box = psrc_box;
struct pipe_box staging_box, dst_box;
if (D3D12_DEBUG_BLIT & d3d12_debug) {
debug_printf("D3D12 COPY: from %s@%d msaa:%d mips:%d %dx%dx%d + %dx%dx%d\n",
util_format_name(psrc->format), src_level, psrc->nr_samples,
psrc->last_level,
psrc_box->x, psrc_box->y, psrc_box->z,
psrc_box->width, psrc_box->height, psrc_box->depth);
debug_printf(" to %s@%d msaa:%d mips:%d %dx%dx%d\n",
util_format_name(pdst->format), dst_level, psrc->nr_samples,
psrc->last_level, dstx, dsty, dstz);
}
/* Use an intermediate resource if copying from/to the same subresource */
if (d3d12_resource_resource(dst) == d3d12_resource_resource(src) && dst_level == src_level) {
staging_res = create_staging_resource(ctx, src, src_level, psrc_box, &staging_box, PIPE_MASK_RGBAZS);
src = d3d12_resource(staging_res);
src_level = 0;
src_box = &staging_box;
}
dst_box.x = dstx;
dst_box.y = dsty;
dst_box.z = static_cast<int16_t>(dstz);
dst_box.width = psrc_box->width;
dst_box.height = psrc_box->height;
d3d12_direct_copy(ctx, dst, dst_level, &dst_box,
src, src_level, src_box, PIPE_MASK_RGBAZS);
if (staging_res)
pipe_resource_reference(&staging_res, NULL);
}
void
d3d12_context_copy_init(struct pipe_context *ctx)
{
ctx->resource_copy_region = d3d12_resource_copy_region;
}
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_DEBUG_H
#define D3D12_DEBUG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define D3D12_DEBUG_VERBOSE (1 << 0)
#define D3D12_DEBUG_EXPERIMENTAL (1 << 1)
#define D3D12_DEBUG_DXIL (1 << 2)
#define D3D12_DEBUG_DISASS (1 << 3)
#define D3D12_DEBUG_BLIT (1 << 4)
#define D3D12_DEBUG_RESOURCE (1 << 5)
#define D3D12_DEBUG_DEBUG_LAYER (1 << 6)
#define D3D12_DEBUG_GPU_VALIDATOR (1 << 7)
#define D3D12_DEBUG_SINGLETON (1 << 8)
#define D3D12_DEBUG_PIX (1 << 9)
extern uint32_t d3d12_debug;
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,243 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_context.h"
#include "d3d12_descriptor_pool.h"
#include "d3d12_screen.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/list.h"
#include "util/u_dynarray.h"
#include "util/u_memory.h"
#include <dxguids/dxguids.h>
struct d3d12_descriptor_pool {
ID3D12Device *dev;
D3D12_DESCRIPTOR_HEAP_TYPE type;
uint32_t num_descriptors;
list_head heaps;
};
struct d3d12_descriptor_heap {
struct d3d12_descriptor_pool *pool;
D3D12_DESCRIPTOR_HEAP_DESC desc;
ID3D12Device *dev;
ID3D12DescriptorHeap *heap;
uint32_t desc_size;
size_t cpu_base;
uint64_t gpu_base;
uint32_t size;
uint32_t next;
util_dynarray free_list;
list_head link;
};
struct d3d12_descriptor_heap*
d3d12_descriptor_heap_new(ID3D12Device *dev,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags,
uint32_t num_descriptors)
{
struct d3d12_descriptor_heap *heap = CALLOC_STRUCT(d3d12_descriptor_heap);
heap->desc.NumDescriptors = num_descriptors;
heap->desc.Type = type;
heap->desc.Flags = flags;
if (FAILED(dev->CreateDescriptorHeap(&heap->desc,
IID_PPV_ARGS(&heap->heap)))) {
FREE(heap);
return NULL;
}
heap->dev = dev;
heap->desc_size = dev->GetDescriptorHandleIncrementSize(type);
heap->size = num_descriptors * heap->desc_size;
heap->cpu_base = GetCPUDescriptorHandleForHeapStart(heap->heap).ptr;
if (flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
heap->gpu_base = GetGPUDescriptorHandleForHeapStart(heap->heap).ptr;
heap->free_list = UTIL_DYNARRAY_INIT;
return heap;
}
void
d3d12_descriptor_heap_free(struct d3d12_descriptor_heap *heap)
{
heap->heap->Release();
util_dynarray_fini(&heap->free_list);
FREE(heap);
}
ID3D12DescriptorHeap*
d3d12_descriptor_heap_get(struct d3d12_descriptor_heap *heap)
{
return heap->heap;
}
static uint32_t
d3d12_descriptor_heap_is_online(struct d3d12_descriptor_heap *heap)
{
return (heap->desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) ? 1 : 0;
}
static uint32_t
d3d12_descriptor_heap_can_allocate(struct d3d12_descriptor_heap *heap)
{
return (heap->free_list.size > 0 ||
heap->size >= heap->next + heap->desc_size);
}
uint32_t
d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap *heap)
{
return (heap->size - heap->next) / heap->desc_size;
}
void
d2d12_descriptor_heap_get_next_handle(struct d3d12_descriptor_heap *heap,
struct d3d12_descriptor_handle *handle)
{
handle->heap = heap;
handle->cpu_handle.ptr = heap->cpu_base + heap->next;
handle->gpu_handle.ptr = d3d12_descriptor_heap_is_online(heap) ?
heap->gpu_base + heap->next : 0;
}
uint32_t
d3d12_descriptor_heap_alloc_handle(struct d3d12_descriptor_heap *heap,
struct d3d12_descriptor_handle *handle)
{
uint32_t offset = 0;
assert(handle != NULL);
if (heap->free_list.size > 0) {
offset = util_dynarray_pop(&heap->free_list, uint32_t);
} else if (heap->size >= heap->next + heap->desc_size) {
offset = heap->next;
heap->next += heap->desc_size;
} else {
/* Todo: we should add a new descriptor heap to get more handles */
assert(0 && "No handles available in descriptor heap");
return 0;
}
handle->heap = heap;
handle->cpu_handle.ptr = heap->cpu_base + offset;
handle->gpu_handle.ptr = d3d12_descriptor_heap_is_online(heap) ?
heap->gpu_base + offset : 0;
return 1;
}
void
d3d12_descriptor_handle_free(struct d3d12_descriptor_handle *handle)
{
const uint32_t index = static_cast<uint32_t>(handle->cpu_handle.ptr - handle->heap->cpu_base);
if (index + handle->heap->desc_size == handle->heap->next) {
handle->heap->next = index;
} else {
util_dynarray_append(&handle->heap->free_list, index);
}
handle->heap = NULL;
handle->cpu_handle.ptr = 0;
handle->gpu_handle.ptr = 0;
}
void
d3d12_descriptor_heap_append_handles(struct d3d12_descriptor_heap *heap,
D3D12_CPU_DESCRIPTOR_HANDLE *handles,
unsigned num_handles)
{
D3D12_CPU_DESCRIPTOR_HANDLE dst;
assert(heap->next + (num_handles * heap->desc_size) <= heap->size);
dst.ptr = heap->cpu_base + heap->next;
heap->dev->CopyDescriptors(1, &dst, &num_handles,
num_handles, handles, NULL,
heap->desc.Type);
heap->next += num_handles * heap->desc_size;
}
void
d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap *heap)
{
heap->next = 0;
util_dynarray_clear(&heap->free_list);
}
struct d3d12_descriptor_pool*
d3d12_descriptor_pool_new(struct d3d12_screen *screen,
D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32_t num_descriptors)
{
struct d3d12_descriptor_pool *pool = CALLOC_STRUCT(d3d12_descriptor_pool);
if (!pool)
return NULL;
pool->dev = screen->dev;
pool->type = type;
pool->num_descriptors = num_descriptors;
list_inithead(&pool->heaps);
return pool;
}
void
d3d12_descriptor_pool_free(struct d3d12_descriptor_pool *pool)
{
list_for_each_entry_safe(struct d3d12_descriptor_heap, heap, &pool->heaps, link) {
list_del(&heap->link);
d3d12_descriptor_heap_free(heap);
}
FREE(pool);
}
uint32_t
d3d12_descriptor_pool_alloc_handle(struct d3d12_descriptor_pool *pool,
struct d3d12_descriptor_handle *handle)
{
struct d3d12_descriptor_heap *valid_heap = NULL;
list_for_each_entry(struct d3d12_descriptor_heap, heap, &pool->heaps, link) {
if (d3d12_descriptor_heap_can_allocate(heap)) {
valid_heap = heap;
break;
}
}
if (!valid_heap) {
valid_heap = d3d12_descriptor_heap_new(pool->dev,
pool->type,
D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
pool->num_descriptors);
list_addtail(&valid_heap->link, &pool->heaps);
}
return d3d12_descriptor_heap_alloc_handle(valid_heap, handle);
}
@@ -0,0 +1,95 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_DESCRIPTOR_POOL_H
#define D3D12_DESCRIPTOR_POOL_H
#include "d3d12_common.h"
struct d3d12_descriptor_pool;
struct d3d12_descriptor_heap;
struct d3d12_descriptor_handle {
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle;
struct d3d12_descriptor_heap *heap;
};
inline bool
d3d12_descriptor_handle_is_allocated(struct d3d12_descriptor_handle *handle)
{
return (handle->heap != NULL);
}
void
d3d12_descriptor_handle_free(struct d3d12_descriptor_handle *handle);
/* Offline Descriptor Pool */
struct d3d12_descriptor_pool*
d3d12_descriptor_pool_new(struct d3d12_screen *screen,
D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32_t num_descriptors);
void
d3d12_descriptor_pool_free(struct d3d12_descriptor_pool *pool);
uint32_t
d3d12_descriptor_pool_alloc_handle(struct d3d12_descriptor_pool *pool,
struct d3d12_descriptor_handle *handle);
/* Online/Offline Descriptor Heaps */
struct d3d12_descriptor_heap*
d3d12_descriptor_heap_new(ID3D12Device *device,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags,
uint32_t num_descriptors);
void
d3d12_descriptor_heap_free(struct d3d12_descriptor_heap *heap);
ID3D12DescriptorHeap*
d3d12_descriptor_heap_get(struct d3d12_descriptor_heap *heap);
void
d2d12_descriptor_heap_get_next_handle(struct d3d12_descriptor_heap *heap,
struct d3d12_descriptor_handle *handle);
uint32_t
d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap *heap);
uint32_t
d3d12_descriptor_heap_alloc_handle(struct d3d12_descriptor_heap *heap,
struct d3d12_descriptor_handle *handle);
void
d3d12_descriptor_heap_append_handles(struct d3d12_descriptor_heap *heap,
D3D12_CPU_DESCRIPTOR_HANDLE *handles,
unsigned num_handles);
void
d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap *heap);
#endif
File diff suppressed because it is too large. Load diff
Loaded 100 of 12511 files, more files were not shown because too many files have changed in this diff. Show more