hasvk: Add host_image_copy, H.264 encode and a batch of gen7 fixes.

Squashed work that had been sitting in the working tree. Grouped by area:

Extensions
  VK_EXT_host_image_copy, with a MEMCPY_BIT path that reads and writes the
  image's own tiled layout, VkSubresourceHostMemcpySizeEXT filled in, and
  VkHostImageCopyDevicePerformanceQueryEXT answered.  Depth/stencil and
  non-power-of-two bpb stay NotSupported.
  VK_EXT_pipeline_robustness, VK_KHR_shader_float_controls2,
  VK_KHR_shader_subgroup_rotate, VK_EXT_vertex_input_dynamic_state,
  VK_EXT_conditional_rendering (an MI_PREDICATE path for gen7, which has no
  GPRs), custom_border_color, border_color_swizzle, map_memory2,
  load_store_op_none, depth_clamp_zero_one,
  dynamic_rendering_unused_attachments, index_type_uint8,
  line_rasterization, vertex_attribute_divisor, mutable_descriptor_type.

H.264 encode
  MFC command emission and a bitstream writer, driving intra-only encode
  through the video queue.  Video profile reporting was also corrected from
  270 combinations down to the 11 that actually exist.

Correctness
  gfx7 routes typed surface writes through the render cache, so
  VK_ACCESS_SHADER_WRITE barriers have to flush it -- without that, nothing a
  fragment shader stored was visible.
  nir_opt_algebraic's fadd->flrp fusion rules dropped signed zero; '~' only
  excludes nir_fp_exact, not preserve_signed_zero, so reflect() with a -0
  input came out wrong.  Guarded with (nsz).
  Stop advertising STORAGE_READ_WITHOUT_FORMAT: shaderStorageImageReadWithout-
  Format is false here, and since Vulkan 1.3 the per-format bit is what grants
  permission, so reporting it while rejecting the pipeline is a contradiction.
  gfx7's typed data port ignores SURFTYPE_NULL -- the null surface still has
  one addressable texel, which read and wrote graphics address zero.  Bounds
  check typed image access against the image param when nullDescriptor is
  enabled, the same trick lower_image_atomic_instr already used on IVB.
  Formats that require a sampler Y'CbCr conversion no longer report
  BLIT_SRC/BLIT_DST/STORAGE_IMAGE.  Video decode does not need them.
  Check the surface state allocations in emit_binding_table() and in the push
  descriptor path instead of writing through a NULL map in release builds.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
elwrclandClaude Opus 5 committed 2026-08-09 00:32:40 +03:00
1 parent 0e4983ca15
commit 636d2c2f70
28 files changed
+2666 -327

No files matched your search

+4 -4
View File
@@ -496,11 +496,11 @@ for s in [16, 32, 64]:
(('~flrp@{}'.format(s), ('fadd(is_used_once)', a, b), ('fadd(is_used_once)', a, c), d), ('fadd', ('flrp', b, c, d), a), 'options->lower_flrp{}'.format(s)),
(('~flrp@{}'.format(s), a, ('fmul(is_used_once)', a, b), c), ('fmul', ('flrp', 1.0, b, c), a), 'options->lower_flrp{}'.format(s)),
(('~fadd@{}'.format(s), ('fmul', a, ('fadd', 1.0, ('fneg', c))), ('fmul', b, c)), ('flrp', a, b, c), '!options->lower_flrp{}'.format(s)),
(('~fadd@{}(nsz)'.format(s), ('fmul', a, ('fadd', 1.0, ('fneg', c))), ('fmul', b, c)), ('flrp', a, b, c), '!options->lower_flrp{}'.format(s)),
# These are the same as the previous three rules, but it depends on
# 1-fsat(x) <=> fsat(1-x). See below.
(('~fadd@{}'.format(s), ('fmul', a, ('fsat', ('fadd', 1.0, ('fneg', c)))), ('fmul', b, ('fsat', c))), ('flrp', a, b, ('fsat', c)), '!options->lower_flrp{}'.format(s)),
(('~fadd@{}'.format(s), a, ('fmul', c, ('fadd', b, ('fneg', a)))), ('flrp', a, b, c), '!options->lower_flrp{}'.format(s)),
(('~fadd@{}(nsz)'.format(s), ('fmul', a, ('fsat', ('fadd', 1.0, ('fneg', c)))), ('fmul', b, ('fsat', c))), ('flrp', a, b, ('fsat', c)), '!options->lower_flrp{}'.format(s)),
(('~fadd@{}(nsz)'.format(s), a, ('fmul', c, ('fadd', b, ('fneg', a)))), ('flrp', a, b, c), '!options->lower_flrp{}'.format(s)),
# 1 - ((1 - a) * (1 - b))
# 1 - (1 - a - b + a*b)
@@ -509,7 +509,7 @@ for s in [16, 32, 64]:
# a + b*(1 - a)
# b*(1 - a) + 1*a
# flrp(b, 1, a)
(('~fadd@{}'.format(s), 1.0, ('fneg', ('fmul', ('fadd', 1.0, ('fneg', a)), ('fadd', 1.0, ('fneg', b))))), ('flrp', b, 1.0, a), '!options->lower_flrp{}'.format(s)),
(('~fadd@{}(nsz)'.format(s), 1.0, ('fneg', ('fmul', ('fadd', 1.0, ('fneg', a)), ('fadd', 1.0, ('fneg', b))))), ('flrp', b, 1.0, a), '!options->lower_flrp{}'.format(s)),
])
optimizations.extend([
+7 -2
View File
@@ -185,14 +185,19 @@ struct elk_sampler_prog_key_data {
enum elk_robustness_flags {
ELK_ROBUSTNESS_UBO = BITFIELD_BIT(0),
ELK_ROBUSTNESS_SSBO = BITFIELD_BIT(1),
/* Bounds check typed image access in the shader instead of relying on the
* hardware. Only needed for null descriptors: gfx7 has no zero-sized
* surface, so the null surface still has one addressable texel.
*/
ELK_ROBUSTNESS_IMAGE = BITFIELD_BIT(2),
};
struct elk_base_prog_key {
unsigned program_string_id;
enum elk_robustness_flags robust_flags:2;
enum elk_robustness_flags robust_flags:3;
unsigned padding:22;
unsigned padding:21;
/**
* Apply workarounds for SIN and COS input range problems.
+6
View File
@@ -199,6 +199,12 @@ struct elk_nir_lower_storage_image_opts {
bool lower_stores;
bool lower_atomics;
bool lower_get_size;
/* Bounds check typed image access against the image param instead of
* trusting the surface. Needed to make null descriptors read as zero and
* swallow their stores; see ELK_ROBUSTNESS_IMAGE.
*/
bool robust_image_access;
};
bool elk_nir_lower_storage_image(nir_shader *nir,
@@ -47,9 +47,16 @@ image_coord_is_in_bounds(nir_builder *b, nir_deref_instr *deref,
nir_def *coord)
{
nir_def *size = load_image_param(b, deref, SIZE);
nir_def *cmp = nir_ilt(b, coord, size);
unsigned coord_comps = glsl_get_sampler_coordinate_components(deref->type);
/* SIZE only carries three components, so a cube array's fourth coordinate
* has no bound to compare against.
*/
unsigned coord_comps =
MIN2(glsl_get_sampler_coordinate_components(deref->type),
size->num_components);
nir_def *cmp = nir_ilt(b, nir_trim_vector(b, coord, coord_comps),
nir_trim_vector(b, size, coord_comps));
nir_def *in_bounds = nir_imm_true(b);
for (unsigned i = 0; i < coord_comps; i++)
in_bounds = nir_iand(b, in_bounds, nir_channel(b, cmp, i));
@@ -57,6 +64,21 @@ image_coord_is_in_bounds(nir_builder *b, nir_deref_instr *deref,
return in_bounds;
}
/* A null descriptor binds the null surface. gfx7's typed data port does not
* honour SURFTYPE_NULL -- and there is no way to describe a zero-sized surface
* either, so the null surface keeps one addressable texel that reads back
* whatever is at graphics address zero and happily absorbs stores. The image
* param is all zeroes for a null descriptor and a real image always has a
* non-zero width, so that is what we test. Same trick lower_image_atomic_instr
* has always used on IVB.
*/
static nir_def *
image_is_bound(nir_builder *b, nir_deref_instr *deref)
{
nir_def *size = load_image_param(b, deref, SIZE);
return nir_ine_imm(b, nir_channel(b, size, 0), 0);
}
/** Calculate the offset in memory of the texel given by \p coord.
*
* This is meant to be used with untyped surface messages to access a tiled
@@ -345,7 +367,8 @@ static bool
lower_image_load_instr(nir_builder *b,
const struct intel_device_info *devinfo,
nir_intrinsic_instr *intrin,
bool sparse)
bool sparse,
bool robust_image_access)
{
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
nir_variable *var = nir_deref_instr_get_variable(deref);
@@ -394,6 +417,18 @@ lower_image_load_instr(nir_builder *b,
color = nir_vec(b, sparse_color, dest_components + 1);
}
/* A null descriptor binds the null surface, which gfx7's typed data
* port does not honour: it still has one addressable texel and there is
* no way to describe a zero-sized surface. Force that last texel to
* read as zero using the image param, which is all-zero for a null
* descriptor.
*/
if (robust_image_access) {
color = nir_bcsel(b, image_is_bound(b, deref), color,
nir_imm_zero(b, color->num_components,
color->bit_size));
}
nir_def_replace(placeholder, color);
} else {
/* This code part is only useful prior to Gfx9, we do not have plans to
@@ -522,7 +557,8 @@ convert_color_for_store(nir_builder *b, const struct intel_device_info *devinfo,
static bool
lower_image_store_instr(nir_builder *b,
const struct intel_device_info *devinfo,
nir_intrinsic_instr *intrin)
nir_intrinsic_instr *intrin,
bool robust_image_access)
{
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
nir_variable *var = nir_deref_instr_get_variable(deref);
@@ -551,6 +587,18 @@ lower_image_store_instr(nir_builder *b,
image_fmt, lower_fmt);
intrin->num_components = isl_format_get_num_channels(lower_fmt);
nir_src_rewrite(&intrin->src[3], color);
/* See the matching comment in lower_image_load_instr(): the null
* surface's one live texel would otherwise absorb the store and hand it
* back on the next load.
*/
if (robust_image_access) {
nir_def *bound = image_is_bound(b, deref);
nir_instr_remove(&intrin->instr);
nir_push_if(b, bound);
nir_builder_instr_insert(b, &intrin->instr);
nir_pop_if(b, NULL);
}
} else {
const struct isl_format_layout *image_fmtl =
isl_format_get_layout(image_fmt);
@@ -602,9 +650,10 @@ lower_image_store_instr(nir_builder *b,
static bool
lower_image_atomic_instr(nir_builder *b,
const struct intel_device_info *devinfo,
nir_intrinsic_instr *intrin)
nir_intrinsic_instr *intrin,
bool robust_image_access)
{
if (devinfo->verx10 >= 75)
if (devinfo->verx10 >= 75 && !robust_image_access)
return false;
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
@@ -694,23 +743,27 @@ elk_nir_lower_storage_image_instr(nir_builder *b,
switch (intrin->intrinsic) {
case nir_intrinsic_image_deref_load:
if (opts->lower_loads)
return lower_image_load_instr(b, opts->devinfo, intrin, false);
return lower_image_load_instr(b, opts->devinfo, intrin, false,
opts->robust_image_access);
return false;
case nir_intrinsic_image_deref_sparse_load:
if (opts->lower_loads)
return lower_image_load_instr(b, opts->devinfo, intrin, true);
return lower_image_load_instr(b, opts->devinfo, intrin, true,
opts->robust_image_access);
return false;
case nir_intrinsic_image_deref_store:
if (opts->lower_stores)
return lower_image_store_instr(b, opts->devinfo, intrin);
return lower_image_store_instr(b, opts->devinfo, intrin,
opts->robust_image_access);
return false;
case nir_intrinsic_image_deref_atomic:
case nir_intrinsic_image_deref_atomic_swap:
if (opts->lower_atomics)
return lower_image_atomic_instr(b, opts->devinfo, intrin);
return lower_image_atomic_instr(b, opts->devinfo, intrin,
opts->robust_image_access);
return false;
case nir_intrinsic_image_deref_size:
+3 -1
View File
@@ -2191,7 +2191,9 @@
<value name="MPEG_INTRA_QUANTIZER_MATRIX" value="0" />
<value name="MPEG_NON_INTRA_QUANTIZER_MATRIX" value="1" />
</field>
<field name="Forward Quantizer Matrix" dword="2" bits="1023:0" type="uint" />
<group count="32" dword="2" size="32">
<field name="Forward Quantizer Matrix" dword="0" bits="31:0" type="uint" />
</group>
</instruction>
<instruction name="MFX_IND_OBJ_BASE_ADDR_STATE" bias="2" length="11" engine="video">
<field name="DWord Length" dword="0" bits="11:0" type="uint" default="9" />
+24 -12
View File
@@ -104,6 +104,8 @@ anv_create_cmd_buffer(struct vk_command_pool *pool,
cmd_buffer->vk.dynamic_graphics_state.ms.sample_locations =
&cmd_buffer->state.gfx.sample_locations;
cmd_buffer->vk.dynamic_graphics_state.vi =
&cmd_buffer->state.gfx.vertex_input;
cmd_buffer->batch.status = VK_SUCCESS;
@@ -806,14 +808,19 @@ anv_cmd_buffer_push_descriptor_sets(struct anv_cmd_buffer *cmd_buffer,
for (uint32_t j = 0; j < write->descriptorCount; j++) {
ANV_FROM_HANDLE(anv_buffer, buffer, write->pBufferInfo[j].buffer);
anv_descriptor_set_write_buffer(cmd_buffer->device, set,
&cmd_buffer->surface_state_stream,
write->descriptorType,
buffer,
write->dstBinding,
write->dstArrayElement + j,
write->pBufferInfo[j].offset,
write->pBufferInfo[j].range);
VkResult result =
anv_descriptor_set_write_buffer(cmd_buffer->device, set,
&cmd_buffer->surface_state_stream,
write->descriptorType,
buffer,
write->dstBinding,
write->dstArrayElement + j,
write->pBufferInfo[j].offset,
write->pBufferInfo[j].range);
if (result != VK_SUCCESS) {
anv_batch_set_error(&cmd_buffer->batch, result);
return;
}
}
break;
@@ -862,10 +869,15 @@ void anv_CmdPushDescriptorSetWithTemplate2KHR(
if (!set)
return;
anv_descriptor_set_write_template(cmd_buffer->device, set,
&cmd_buffer->surface_state_stream,
template,
pInfo->pData);
VkResult result =
anv_descriptor_set_write_template(cmd_buffer->device, set,
&cmd_buffer->surface_state_stream,
template,
pInfo->pData);
if (result != VK_SUCCESS) {
anv_batch_set_error(&cmd_buffer->batch, result);
return;
}
anv_cmd_buffer_bind_descriptor_set(cmd_buffer, template->bind_point,
pipeline_layout, pInfo->set, set, NULL, NULL);
+36 -13
View File
@@ -1543,7 +1543,7 @@ anv_descriptor_set_write_buffer_view(struct anv_device *device,
}
}
void
VkResult
anv_descriptor_set_write_buffer(struct anv_device *device,
struct anv_descriptor_set *set,
struct anv_state_stream *alloc_stream,
@@ -1572,14 +1572,14 @@ anv_descriptor_set_write_buffer(struct anv_device *device,
};
if (set->pool && set->pool->host_only)
return;
return VK_SUCCESS;
void *desc_map = set->desc_mem.map + bind_layout->descriptor_offset +
element * bind_layout->descriptor_stride;
if (buffer == NULL) {
memset(desc_map, 0, bind_layout->descriptor_stride);
return;
return VK_SUCCESS;
}
struct anv_address bind_addr = anv_address_add(buffer->address, offset);
@@ -1605,7 +1605,7 @@ anv_descriptor_set_write_buffer(struct anv_device *device,
}
if (vk_descriptor_type_is_dynamic(type))
return;
return VK_SUCCESS;
assert(data & ANV_DESCRIPTOR_BUFFER_VIEW);
struct anv_buffer_view *bview =
@@ -1620,6 +1620,13 @@ anv_descriptor_set_write_buffer(struct anv_device *device,
* vkAllocateDescriptorSets. */
if (alloc_stream) {
bview->surface_state = anv_state_stream_alloc(alloc_stream, 64, 64);
/* The stream is backed by the command buffer's surface state block; it
* can run dry. anv_fill_buffer_surface_state() would then write through
* a NULL map, which is a SIGBUS in release builds because the assert
* below is compiled out.
*/
if (bview->surface_state.map == NULL)
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
}
assert(bview->surface_state.alloc_size);
@@ -1635,6 +1642,8 @@ anv_descriptor_set_write_buffer(struct anv_device *device,
format, ISL_SWIZZLE_IDENTITY,
usage, bind_addr, bind_range, 1);
desc->set_buffer_view = bview;
return VK_SUCCESS;
}
void
@@ -1704,6 +1713,7 @@ void anv_UpdateDescriptorSets(
for (uint32_t j = 0; j < write->descriptorCount; j++) {
ANV_FROM_HANDLE(anv_buffer, buffer, write->pBufferInfo[j].buffer);
ASSERTED VkResult result =
anv_descriptor_set_write_buffer(device, set,
NULL,
write->descriptorType,
@@ -1712,6 +1722,9 @@ void anv_UpdateDescriptorSets(
write->dstArrayElement + j,
write->pBufferInfo[j].offset,
write->pBufferInfo[j].range);
/* No alloc_stream, so the surface state comes from the pool and
* this cannot fail. */
assert(result == VK_SUCCESS);
}
break;
@@ -1789,6 +1802,7 @@ void anv_UpdateDescriptorSets(
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
ASSERTED VkResult result =
anv_descriptor_set_write_buffer(device, dst,
NULL,
src_desc[j].type,
@@ -1797,6 +1811,7 @@ void anv_UpdateDescriptorSets(
copy->dstArrayElement + j,
src_desc[j].offset,
src_desc[j].range);
assert(result == VK_SUCCESS);
break;
}
@@ -1811,7 +1826,7 @@ void anv_UpdateDescriptorSets(
* Descriptor update templates.
*/
void
VkResult
anv_descriptor_set_write_template(struct anv_device *device,
struct anv_descriptor_set *set,
struct anv_state_stream *alloc_stream,
@@ -1862,13 +1877,16 @@ anv_descriptor_set_write_template(struct anv_device *device,
data + entry->offset + j * entry->stride;
ANV_FROM_HANDLE(anv_buffer, buffer, info->buffer);
anv_descriptor_set_write_buffer(device, set,
alloc_stream,
entry->type,
buffer,
entry->binding,
entry->array_element + j,
info->offset, info->range);
VkResult result =
anv_descriptor_set_write_buffer(device, set,
alloc_stream,
entry->type,
buffer,
entry->binding,
entry->array_element + j,
info->offset, info->range);
if (result != VK_SUCCESS)
return result;
}
break;
@@ -1884,6 +1902,8 @@ anv_descriptor_set_write_template(struct anv_device *device,
break;
}
}
return VK_SUCCESS;
}
void anv_UpdateDescriptorSetWithTemplate(
@@ -1897,5 +1917,8 @@ void anv_UpdateDescriptorSetWithTemplate(
VK_FROM_HANDLE(vk_descriptor_update_template, template,
descriptorUpdateTemplate);
anv_descriptor_set_write_template(device, set, NULL, template, pData);
/* No alloc_stream, so nothing here allocates and this cannot fail. */
ASSERTED VkResult result =
anv_descriptor_set_write_template(device, set, NULL, template, pData);
assert(result == VK_SUCCESS);
}
+121 -30
View File
@@ -99,6 +99,7 @@ static const driOptionDescription anv_dri_options[] = {
static const struct debug_control debug_control[] = {
{ "video-decode", ANV_DEBUG_VIDEO_DECODE },
{ "video-debug", ANV_DEBUG_VIDEO_DEBUG },
{ "video-encode", ANV_DEBUG_VIDEO_ENCODE },
{ NULL, 0 }
};
@@ -206,7 +207,10 @@ get_device_extensions(const struct anv_physical_device *device,
const bool has_syncobj_wait =
(device->sync_syncobj_type.features & VK_SYNC_FEATURE_CPU_WAIT) != 0;
const bool video_decode = VIDEO_CODEC_H264DEC && ANV_DEBUG(VIDEO_DECODE);
/* Video extensions are advertised by default (not gated behind
* HASVK_DEBUG); the compile-time VIDEO_CODEC_* configuration still applies. */
const bool video_decode = VIDEO_CODEC_H264DEC;
const bool video_encode = VIDEO_CODEC_H264ENC;
*ext = (struct vk_device_extension_table) {
.KHR_8bit_storage = device->info.ver >= 8,
@@ -217,6 +221,7 @@ get_device_extensions(const struct anv_physical_device *device,
.KHR_create_renderpass2 = true,
.KHR_dedicated_allocation = true,
.KHR_deferred_host_operations = true,
.KHR_depth_clamp_zero_one = true,
.KHR_depth_stencil_resolve = true,
.KHR_descriptor_update_template = true,
.KHR_device_group = true,
@@ -233,6 +238,7 @@ get_device_extensions(const struct anv_physical_device *device,
.KHR_get_memory_requirements2 = true,
.KHR_image_format_list = true,
.KHR_imageless_framebuffer = true,
.KHR_load_store_op_none = true,
#ifdef ANV_USE_WSI_PLATFORM
.KHR_incremental_present = true,
#endif
@@ -264,10 +270,12 @@ get_device_extensions(const struct anv_physical_device *device,
.KHR_shader_expect_assume = true,
.KHR_shader_float16_int8 = device->info.ver >= 8 && !device->instance->no_16bit,
.KHR_shader_float_controls = true,
.KHR_shader_float_controls2 = true,
.KHR_shader_integer_dot_product = true,
.KHR_shader_non_semantic_info = true,
.KHR_shader_relaxed_extended_instruction = true,
.KHR_shader_subgroup_extended_types = device->info.ver >= 8,
.KHR_shader_subgroup_rotate = true,
.KHR_shader_subgroup_uniform_control_flow = true,
.KHR_shader_terminate_invocation = true,
.KHR_spirv_1_4 = true,
@@ -276,11 +284,13 @@ get_device_extensions(const struct anv_physical_device *device,
.KHR_swapchain = true,
.KHR_swapchain_mutable_format = true,
#endif
.KHR_video_queue = video_decode,
.KHR_video_queue = video_decode || video_encode,
.KHR_video_decode_queue = video_decode,
.KHR_video_decode_h264 = video_decode,
.KHR_video_maintenance1 = video_decode,
.KHR_video_maintenance2 = video_decode,
.KHR_video_encode_queue = video_encode,
.KHR_video_encode_h264 = video_encode,
.KHR_video_maintenance1 = video_decode || video_encode,
.KHR_video_maintenance2 = video_decode || video_encode,
.KHR_synchronization2 = true,
.KHR_timeline_semaphore = true,
.KHR_internally_synchronized_queues = true,
@@ -290,12 +300,12 @@ get_device_extensions(const struct anv_physical_device *device,
.KHR_workgroup_memory_explicit_layout = true,
.KHR_zero_initialize_workgroup_memory = true,
.EXT_4444_formats = true,
.EXT_border_color_swizzle = device->info.ver >= 8,
.EXT_border_color_swizzle = device->info.ver >= 7,
.EXT_buffer_device_address = device->has_a64_buffer_access,
.EXT_calibrated_timestamps = device->has_reg_timestamp,
.EXT_color_write_enable = true,
.EXT_conditional_rendering = device->info.verx10 >= 75,
.EXT_custom_border_color = device->info.ver >= 8,
.EXT_conditional_rendering = device->info.verx10 >= 70,
.EXT_custom_border_color = device->info.ver >= 7,
.EXT_debug_marker = true,
.EXT_depth_clamp_zero_one = true,
.EXT_depth_clamp_control = true,
@@ -304,6 +314,7 @@ get_device_extensions(const struct anv_physical_device *device,
#ifdef VK_USE_PLATFORM_DISPLAY_KHR
.EXT_display_control = true,
#endif
.EXT_dynamic_rendering_unused_attachments = true,
.EXT_extended_dynamic_state = true,
.EXT_extended_dynamic_state2 = true,
.EXT_external_memory_dma_buf = true,
@@ -312,14 +323,19 @@ get_device_extensions(const struct anv_physical_device *device,
INTEL_CONTEXT_MEDIUM_PRIORITY,
.EXT_global_priority_query = device->max_context_priority >=
INTEL_CONTEXT_MEDIUM_PRIORITY,
.EXT_host_image_copy = true,
.EXT_host_query_reset = true,
.EXT_image_2d_view_of_3d = true,
.EXT_image_robustness = true,
.EXT_image_drm_format_modifier = true,
.EXT_image_view_min_lod = true,
.EXT_index_type_uint8 = true,
.KHR_index_type_uint8 = true,
.EXT_inline_uniform_block = true,
.EXT_line_rasterization = true,
.KHR_line_rasterization = true,
.EXT_load_store_op_none = true,
.KHR_map_memory2 = true,
/* Enable the extension only if we have support on both the local &
* system memory
*/
@@ -329,6 +345,7 @@ get_device_extensions(const struct anv_physical_device *device,
.EXT_physical_device_drm = true,
.EXT_pipeline_creation_cache_control = true,
.EXT_pipeline_creation_feedback = true,
.EXT_pipeline_robustness = true,
.EXT_primitives_generated_query = true,
.EXT_primitive_topology_list_restart = true,
.EXT_private_data = true,
@@ -350,6 +367,8 @@ get_device_extensions(const struct anv_physical_device *device,
.EXT_tooling_info = true,
.EXT_transform_feedback = true,
.EXT_vertex_attribute_divisor = true,
.EXT_vertex_input_dynamic_state = true,
.KHR_vertex_attribute_divisor = true,
.EXT_ycbcr_image_arrays = true,
#if DETECT_OS_ANDROID
.ANDROID_external_memory_android_hardware_buffer = true,
@@ -364,6 +383,7 @@ get_device_extensions(const struct anv_physical_device *device,
.EXT_multi_draw = true,
.NV_compute_shader_derivatives = true,
.VALVE_mutable_descriptor_type = true,
.EXT_mutable_descriptor_type = true
};
}
@@ -511,6 +531,9 @@ get_features(const struct anv_physical_device *pdevice,
.formatA4R4G4B4 = true,
.formatA4B4G4R4 = false,
/* VK_EXT_host_image_copy */
.hostImageCopy = true,
/* VK_EXT_border_color_swizzle */
.borderColorSwizzle = true,
.borderColorSwizzleFromImage = true,
@@ -527,12 +550,12 @@ get_features(const struct anv_physical_device *pdevice,
.computeDerivativeGroupLinear = true,
/* VK_EXT_conditional_rendering */
.conditionalRendering = pdevice->info.verx10 >= 75,
.conditionalRendering = pdevice->info.verx10 >= 70,
.inheritedConditionalRendering = pdevice->info.verx10 >= 75,
/* VK_EXT_custom_border_color */
.customBorderColors = pdevice->info.ver >= 8,
.customBorderColorWithoutFormat = pdevice->info.ver >= 8,
.customBorderColors = pdevice->info.ver >= 7,
.customBorderColorWithoutFormat = pdevice->info.ver >= 7,
/* VK_EXT_depth_clamp_zero_one */
.depthClampZeroOne = true,
@@ -594,6 +617,9 @@ get_features(const struct anv_physical_device *pdevice,
.robustImageAccess2 = true,
.nullDescriptor = true,
/* VK_EXT_pipeline_robustness */
.pipelineRobustness = true,
/* VK_EXT_shader_atomic_float */
.shaderBufferFloat32Atomics = true,
.shaderBufferFloat32AtomicAdd = pdevice->info.has_lsc,
@@ -619,9 +645,16 @@ get_features(const struct anv_physical_device *pdevice,
/* VK_EXT_shader_module_identifier */
.shaderModuleIdentifier = true,
/* VK_KHR_shader_float_controls2 */
.shaderFloatControls2 = true,
/* VK_EXT_shader_replicated_composites */
.shaderReplicatedComposites = true,
/* VK_KHR_shader_subgroup_rotate */
.shaderSubgroupRotate = true,
.shaderSubgroupRotateClustered = true,
/* VK_KHR_shader_subgroup_uniform_control_flow */
.shaderSubgroupUniformControlFlow = true,
@@ -645,6 +678,9 @@ get_features(const struct anv_physical_device *pdevice,
/* VK_EXT_ycbcr_image_arrays */
.ycbcrImageArrays = true,
/* VK_EXT_dynamic_rendering_unused_attachments */
.dynamicRenderingUnusedAttachments = true,
/* VK_EXT_extended_dynamic_state */
.extendedDynamicState = true,
@@ -653,6 +689,9 @@ get_features(const struct anv_physical_device *pdevice,
.extendedDynamicState2LogicOp = true,
.extendedDynamicState2PatchControlPoints = false,
/* VK_EXT_vertex_input_dynamic_state */
.vertexInputDynamicState = true,
/* VK_EXT_multi_draw */
.multiDraw = true,
@@ -744,7 +783,9 @@ get_properties_1_1(const struct anv_physical_device *pdevice,
VK_SUBGROUP_FEATURE_BALLOT_BIT |
VK_SUBGROUP_FEATURE_SHUFFLE_BIT |
VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT |
VK_SUBGROUP_FEATURE_QUAD_BIT;
VK_SUBGROUP_FEATURE_QUAD_BIT |
VK_SUBGROUP_FEATURE_ROTATE_BIT_KHR |
VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT_KHR;
if (pdevice->info.ver >= 8) {
/* TODO: There's no technical reason why these can't be made to
* work on gfx7 but they don't at the moment so it's best to leave
@@ -1215,6 +1256,22 @@ get_properties(const struct anv_physical_device *pdevice,
props->lineSubPixelPrecisionBits = 4;
}
/* VK_EXT_host_image_copy */
{
static const VkImageLayout host_copy_layouts[] = {
VK_IMAGE_LAYOUT_GENERAL,
};
props->copySrcLayoutCount = ARRAY_SIZE(host_copy_layouts);
props->pCopySrcLayouts = (VkImageLayout *)host_copy_layouts;
props->copyDstLayoutCount = ARRAY_SIZE(host_copy_layouts);
props->pCopyDstLayouts = (VkImageLayout *)host_copy_layouts;
props->identicalMemoryTypeRequirements = true;
memcpy(props->optimalTilingLayoutUUID, pdevice->driver_uuid,
VK_UUID_SIZE);
}
/* VK_EXT_multi_draw */
{
props->maxMultiDrawCount = 2048;
@@ -1238,6 +1295,21 @@ get_properties(const struct anv_physical_device *pdevice,
props->drmRenderMinor = pdevice->local_minor;
}
/* VK_EXT_pipeline_robustness */
{
/* Intel HW bounds-checks vertex fetch and image/texel access
* unconditionally, so the device default is robust for those; buffer
* access is unchecked unless robustBufferAccess is enabled. */
props->defaultRobustnessStorageBuffers =
VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT;
props->defaultRobustnessUniformBuffers =
VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT;
props->defaultRobustnessVertexInputs =
VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
props->defaultRobustnessImages =
VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT;
}
/* VK_EXT_provoking_vertex */
{
props->provokingVertexModePerPipeline = true;
@@ -1594,17 +1666,26 @@ anv_physical_device_init_queue_families(struct anv_physical_device *pdevice)
.engine_class = INTEL_ENGINE_CLASS_RENDER,
};
}
if (v_count > 0 && VIDEO_CODEC_H264DEC && ANV_DEBUG(VIDEO_DECODE)) {
/* Video queues are exposed by default (not gated behind HASVK_DEBUG);
* the compile-time VIDEO_CODEC_* configuration still applies. */
if (v_count > 0 && VIDEO_CODEC_H264DEC) {
pdevice->queue.families[family_count++] = (struct anv_queue_family) {
.queueFlags = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
.queueCount = v_count,
.engine_class = INTEL_ENGINE_CLASS_VIDEO,
};
}
/* Increase count below when other families are added as a reminder to
if (v_count > 0 && VIDEO_CODEC_H264ENC) {
pdevice->queue.families[family_count++] = (struct anv_queue_family) {
.queueFlags = VK_QUEUE_VIDEO_ENCODE_BIT_KHR,
.queueCount = v_count,
.engine_class = INTEL_ENGINE_CLASS_VIDEO,
};
}
/* Increase count below when other families are added and
* increase the ANV_MAX_QUEUE_FAMILIES value.
*/
STATIC_ASSERT(ANV_MAX_QUEUE_FAMILIES >= 3);
STATIC_ASSERT(ANV_MAX_QUEUE_FAMILIES >= 4);
} else {
/* Default to a single render queue */
pdevice->queue.families[family_count++] = (struct anv_queue_family) {
@@ -2135,7 +2216,8 @@ void anv_GetPhysicalDeviceQueueFamilyProperties2(
* to write the query result to memory. The VCS seemingly
* cannot do a posted memory write. */
prop->queryResultStatusSupport =
(queue_family->queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ?
(queue_family->queueFlags & (VK_QUEUE_VIDEO_DECODE_BIT_KHR |
VK_QUEUE_VIDEO_ENCODE_BIT_KHR)) ?
VK_FALSE : VK_TRUE;
break;
}
@@ -2145,6 +2227,9 @@ void anv_GetPhysicalDeviceQueueFamilyProperties2(
if (queue_family->queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
prop->videoCodecOperations =
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR;
} else if (queue_family->queueFlags & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) {
prop->videoCodecOperations =
VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR;
}
break;
}
@@ -2684,7 +2769,7 @@ VkResult anv_CreateDevice(
if (result != VK_SUCCESS)
goto fail_general_state_pool;
if (device->info->ver >= 8) {
if (device->info->ver >= 7) {
/* The border color pointer is limited to 24 bits, so we need to make
* sure that any such color used at any point in the program doesn't
* exceed that limit.
@@ -2818,7 +2903,7 @@ VkResult anv_CreateDevice(
fail_instruction_state_pool:
anv_state_pool_finish(&device->instruction_state_pool);
fail_dynamic_state_pool:
if (device->info->ver >= 8)
if (device->info->ver >= 7)
anv_state_reserved_pool_finish(&device->custom_border_colors);
anv_state_pool_finish(&device->dynamic_state_pool);
fail_general_state_pool:
@@ -2870,7 +2955,7 @@ void anv_DestroyDevice(
/* We only need to free these to prevent valgrind errors. The backing
* BO will go away in a couple of lines so we don't actually leak.
*/
if (device->info->ver >= 8)
if (device->info->ver >= 7)
anv_state_reserved_pool_finish(&device->custom_border_colors);
anv_state_pool_free(&device->dynamic_state_pool, device->border_colors);
anv_state_pool_free(&device->dynamic_state_pool, device->slice_hash);
@@ -3355,8 +3440,11 @@ void anv_FreeMemory(
list_del(&mem->link);
pthread_mutex_unlock(&device->mutex);
if (mem->map)
anv_UnmapMemory(_device, _mem);
const VkMemoryUnmapInfoKHR unmap = {
.sType = VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR,
.memory = _mem,
};
anv_UnmapMemory2KHR(_device, &unmap);
p_atomic_add(&device->physical->memory.heaps[mem->type->heapIndex].used,
-mem->bo->size);
@@ -3371,16 +3459,17 @@ void anv_FreeMemory(
vk_object_free(&device->vk, pAllocator, mem);
}
VkResult anv_MapMemory(
VkResult anv_MapMemory2KHR(
VkDevice _device,
VkDeviceMemory _memory,
VkDeviceSize offset,
VkDeviceSize size,
VkMemoryMapFlags flags,
const VkMemoryMapInfoKHR* pMemoryMapInfo,
void** ppData)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_device_memory, mem, _memory);
ANV_FROM_HANDLE(anv_device_memory, mem, pMemoryMapInfo->memory);
const VkDeviceSize offset = pMemoryMapInfo->offset;
VkDeviceSize size = pMemoryMapInfo->size;
const VkMemoryMapFlags flags = pMemoryMapInfo->flags;
if (mem == NULL) {
*ppData = NULL;
@@ -3462,21 +3551,23 @@ VkResult anv_MapMemory(
return VK_SUCCESS;
}
void anv_UnmapMemory(
VkResult anv_UnmapMemory2KHR(
VkDevice _device,
VkDeviceMemory _memory)
const VkMemoryUnmapInfoKHR* pMemoryUnmapInfo)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_device_memory, mem, _memory);
ANV_FROM_HANDLE(anv_device_memory, mem, pMemoryUnmapInfo->memory);
if (mem == NULL || mem->host_ptr)
return;
return VK_SUCCESS;
anv_device_unmap_bo(device, mem->bo, mem->map, mem->map_size);
mem->map = NULL;
mem->map_size = 0;
mem->map_delta = 0;
return VK_SUCCESS;
}
VkResult anv_FlushMappedMemoryRanges(
+62 -17
View File
@@ -593,7 +593,7 @@ anv_get_image_format_features2(const struct intel_device_info *devinfo,
VK_FORMAT_FEATURE_2_BLIT_SRC_BIT |
VK_FORMAT_FEATURE_2_BLIT_DST_BIT |
VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT;
VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT ;
if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
flags |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
@@ -606,9 +606,14 @@ anv_get_image_format_features2(const struct intel_device_info *devinfo,
if ((anv_format->flags & ANV_FORMAT_FLAG_CAN_VIDEO) &&
(anv_format->n_planes > 1 || vk_tiling == VK_IMAGE_TILING_OPTIMAL)) {
flags |= (VIDEO_CODEC_H264DEC && ANV_DEBUG(VIDEO_DECODE)) ?
/* Video format features are exposed by default (not gated behind
* HASVK_DEBUG). */
flags |= VIDEO_CODEC_H264DEC ?
VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR |
VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR : 0;
flags |= VIDEO_CODEC_H264ENC ?
VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR |
VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR : 0;
}
assert(aspects & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV);
@@ -665,9 +670,18 @@ anv_get_image_format_features2(const struct intel_device_info *devinfo,
/* Load/store is determined based on base format. This prevents RGB
* formats from showing up as load/store capable.
*
* We never advertise STORAGE_READ_WITHOUT_FORMAT because
* shaderStorageImageReadWithoutFormat is always false here: storage image
* surface state is programmed with isl_lower_storage_image_format(), so a
* formatless typed read returns raw bits for every format that gets
* lowered. Since Vulkan 1.3 keys formatless reads off this per-format bit
* rather than off the device feature, advertising it while
* anv_pipeline.c rejects such shaders with VK_ERROR_FEATURE_NOT_PRESENT is
* a contradiction. Enabling the feature instead is not an option either:
* it would claim formatless reads for every extended storage format, which
* is exactly the set we cannot do.
*/
if (isl_format_supports_typed_reads(devinfo, base_isl_format))
flags |= VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT;
if (isl_format_supports_typed_writes(devinfo, base_isl_format))
flags |= VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
@@ -741,18 +755,18 @@ anv_get_image_format_features2(const struct intel_device_info *devinfo,
if (anv_format->n_planes > 1)
flags |= VK_FORMAT_FEATURE_2_DISJOINT_BIT;
/* Formats that require a sampler Y'CbCr conversion may not report any of
* these, video capable or not -- a decode DPB/output image does not need
* them, and anything that wants to blit or store goes through a
* single-plane view of one plane, whose format is not a YCbCr format and
* so keeps its own feature bits.
*/
VkFormatFeatureFlags2 disallowed_ycbcr_image_features =
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT;
/* For video decode formats, allow BLIT and STORAGE operations. */
if (!(flags & (VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR |
VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR))) {
disallowed_ycbcr_image_features |=
VK_FORMAT_FEATURE_2_BLIT_SRC_BIT |
VK_FORMAT_FEATURE_2_BLIT_DST_BIT |
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
}
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT |
VK_FORMAT_FEATURE_2_BLIT_SRC_BIT |
VK_FORMAT_FEATURE_2_BLIT_DST_BIT |
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
flags &= ~disallowed_ycbcr_image_features;
}
@@ -822,6 +836,15 @@ anv_get_image_format_features2(const struct intel_device_info *devinfo,
}
}
/* VK_EXT_host_image_copy: CPU tarafinda isl tiled memcpy kullaniyoruz.
* Power-of-two olmayan bpb'li formatlarda (orn. r32g32b32_sfloat)
* isl'in span matematigi tasma yapiyor, onlari disarida birakiyoruz.
*/
if ((flags & (VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT)) &&
util_is_power_of_two_or_zero(isl_format_layouts[base_isl_format].bpb))
flags |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT;
return flags;
}
@@ -862,8 +885,9 @@ get_buffer_format_features2(const struct intel_device_info *devinfo,
if (isl_format == ISL_FORMAT_R32_SINT || isl_format == ISL_FORMAT_R32_UINT)
flags |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
if (isl_format_supports_typed_reads(devinfo, isl_format))
flags |= VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT;
/* No STORAGE_READ_WITHOUT_FORMAT here either, for the same reason as in
* anv_get_image_format_features2().
*/
if (isl_format_supports_typed_writes(devinfo, isl_format))
flags |= VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
@@ -1241,6 +1265,13 @@ anv_get_image_format_properties(
}
}
if (view_usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) {
if (!(format_feature_flags &
VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT)) {
goto unsupported;
}
}
if (view_usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
if (!(format_feature_flags & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT)) {
goto unsupported;
@@ -1493,12 +1524,16 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2(
/* Extract output structs */
VkDrmFormatModifierPropertiesListEXT *modifier_props = NULL;
VkDrmFormatModifierPropertiesList2EXT *modifier_props_2 = NULL;
VkHostImageCopyDevicePerformanceQueryEXT *host_props = NULL;
vk_foreach_struct(s, base_props->pNext) {
switch (s->sType) {
switch ((unsigned)s->sType) {
case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
external_props = (void *) s;
break;
case VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT:
host_props = (void *) s;
break;
case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES:
ycbcr_props = (void *) s;
break;
@@ -1680,6 +1715,16 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2(
modifier_props_2);
}
/* VK_EXT_host_image_copy performans sorgusu. Gen7'de host-transfer
* imajlari icin suboptimal bir yerlesim zorlamiyoruz (Tile64/Yf/Ys yok,
* bu formatlar aux'suz saklaniyor), dolayisiyla cihaz erisimi optimaldir.
* Bellek yerlesimi ancak LINEAR tiling'de host tarafiyla ayni olur. */
if (host_props) {
host_props->optimalDeviceAccess = VK_TRUE;
host_props->identicalMemoryLayout =
base_info->tiling != VK_IMAGE_TILING_OPTIMAL;
}
return VK_SUCCESS;
fail:
+47
View File
@@ -69,8 +69,40 @@ void genX(cmd_buffer_update_dirty_vbs_for_gfx8_vb_flush)(struct anv_cmd_buffer *
uint64_t vb_used);
void genX(flush_pipeline_select_3d)(struct anv_cmd_buffer *cmd_buffer);
void genX(flush_pipeline_select_media)(struct anv_cmd_buffer *cmd_buffer);
void genX(flush_pipeline_select_gpgpu)(struct anv_cmd_buffer *cmd_buffer);
/* Emits the MFC/MFX static state and per-MB PAK objects for one H.264 encode.
* Defined in anv_video_mfc.c (a separate TU due to the genX_pack.h /
* genX_video_pack.h include-guard collision; see that file's header). */
/* Emits the frame-level MFC/MFX static state (everything up to but not
* including the slices). Call once per frame, before emitting any slice. */
void genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
const struct anv_image *source_image,
struct anv_address recon_address,
const StdVideoH264SequenceParameterSet *sps,
const StdVideoH264PictureParameterSet *pps,
struct anv_address dst_address,
uint32_t dst_page_offset,
uint64_t dst_buffer_range,
uint32_t width_in_mbs, uint32_t height_in_mbs,
bool is_p, struct anv_address ref_address);
/* Emits one slice: MFX_AVC_SLICE_STATE, the slice-header insert, the per-MB
* PAK objects for the macroblock range [slice_start_mb, slice_end_mb), and the
* slice tail. Call once per slice, after the frame-level static state. Intra
* neighbour availability is computed relative to slice_start_mb so it matches
* the decoder (intra prediction does not cross slice boundaries). */
void genX(hasvk_mfc_emit_slice)(struct anv_cmd_buffer *cmd_buffer,
const StdVideoH264SequenceParameterSet *sps,
const StdVideoH264PictureParameterSet *pps,
const StdVideoEncodeH264PictureInfo *pic_info,
const StdVideoEncodeH264SliceHeader *slice_hdr,
uint32_t slice_start_mb, uint32_t slice_end_mb,
uint32_t width_in_mbs, uint32_t height_in_mbs,
uint32_t qp, bool is_last_slice,
uint32_t dst_page_offset);
enum anv_pipe_bits
genX(emit_apply_pipe_flushes)(struct anv_batch *batch,
struct anv_device *device,
@@ -115,6 +147,11 @@ genX(emit_urb_setup)(struct anv_device *device, struct anv_batch *batch,
VkShaderStageFlags active_stages,
const unsigned entry_size[4]);
void
genX(emit_vertex_input)(struct anv_graphics_pipeline *pipeline,
struct anv_batch *batch,
const struct vk_vertex_input_state *vi);
void genX(emit_multisample)(struct anv_batch *batch, uint32_t samples,
const struct vk_sample_locations_state *sl);
@@ -165,3 +202,13 @@ void
genX(emit_query_mi_flush_availability)(struct anv_cmd_buffer *cmd_buffer,
struct anv_address addr,
bool available);
void
genX(emit_query_mi_write_u64)(struct anv_cmd_buffer *cmd_buffer,
struct anv_address addr,
uint64_t value);
void
genX(emit_query_mi_write_reg32)(struct anv_cmd_buffer *cmd_buffer,
struct anv_address addr,
uint32_t reg);
@@ -0,0 +1,429 @@
/*
* VK_EXT_host_image_copy for hasvk (Gen7/7.5)
*/
#include "anv_private.h"
#include "isl/isl.h"
#include "util/u_math.h"
#include "util/os_memory.h"
struct host_copy_map {
void *map; /* BO'nun CPU adresi */
bool mapped_here; /* biz mi map ettik, unmap gerekiyor mu */
struct anv_address addr;
};
static VkResult
host_copy_map_plane(struct anv_device *device,
const struct anv_image *image,
uint32_t plane,
struct host_copy_map *out)
{
const struct anv_image_memory_range *range =
&image->planes[plane].primary_surface.memory_range;
out->addr = anv_image_address(image, range);
if (out->addr.bo == NULL)
return VK_ERROR_MEMORY_MAP_FAILED;
out->map = out->addr.bo->map;
out->mapped_here = false;
if (out->map == NULL) {
VkResult r = anv_device_map_bo(device, out->addr.bo, 0,
out->addr.bo->size, 0, &out->map);
if (r != VK_SUCCESS)
return r;
out->mapped_here = true;
}
return VK_SUCCESS;
}
static void
host_copy_unmap_plane(struct anv_device *device, struct host_copy_map *m)
{
if (m->mapped_here)
anv_device_unmap_bo(device, m->addr.bo, m->map, m->addr.bo->size);
}
/* crocus'taki get_image_offset_el() karsiligi: 3D ile array ayrimi */
static void
host_copy_get_image_offset_el(const struct isl_surf *surf,
uint32_t level, uint32_t z,
uint32_t *out_x0_el, uint32_t *out_y0_el)
{
ASSERTED uint32_t z0_el, a0_el;
if (surf->dim == ISL_SURF_DIM_3D) {
isl_surf_get_image_offset_el(surf, level, 0, z,
out_x0_el, out_y0_el, &z0_el, &a0_el);
} else {
isl_surf_get_image_offset_el(surf, level, z, 0,
out_x0_el, out_y0_el, &z0_el, &a0_el);
}
assert(z0_el == 0 && a0_el == 0);
}
/* crocus'taki tile_extents() karsiligi: x'ler byte, y'ler element satiri */
static void
host_copy_tile_extents(const struct isl_surf *surf,
const VkOffset3D *offset,
const VkExtent3D *extent,
uint32_t level, uint32_t layer,
uint32_t *x1_B, uint32_t *x2_B,
uint32_t *y1_el, uint32_t *y2_el)
{
const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
const unsigned cpp = fmtl->bpb / 8;
uint32_t x0_el, y0_el;
host_copy_get_image_offset_el(surf, level, layer, &x0_el, &y0_el);
assert(offset->x % fmtl->bw == 0);
assert(offset->y % fmtl->bh == 0);
*x1_B = (offset->x / fmtl->bw + x0_el) * cpp;
*y1_el = offset->y / fmtl->bh + y0_el;
*x2_B = (DIV_ROUND_UP(offset->x + extent->width, fmtl->bw) + x0_el) * cpp;
*y2_el = DIV_ROUND_UP(offset->y + extent->height, fmtl->bh) + y0_el;
}
/* isl'in tiled memcpy'si linear taraftan 16-byte hizali bir baslangic
* bekliyor (bkz. crocus_map_tiled_memcpy). Uygulamanin verdigi host
* pointer keyfi hizali olabilecegi icin arada hizali bir buffer
* kullaniyoruz. Buffer'i tam satir pitch'i uzerinden ve fazladan pay
* birakarak ayiriyoruz: isl'in "faster" kopyalayicilari 16 byte'lik
* bloklar halinde calisiyor ve bolge sonunu bir miktar asabiliyor.
*/
static void *
host_copy_alloc_bounce(uint32_t bounce_pitch, uint32_t rows,
uint32_t x1_B, uint8_t **bounce_out)
{
void *base = os_malloc_aligned((size_t)bounce_pitch * (rows + 2) + 128, 16);
if (base == NULL)
return NULL;
*bounce_out = (uint8_t *)base + (x1_B & 0xf);
return base;
}
VkResult anv_CopyMemoryToImageEXT(
VkDevice _device,
const VkCopyMemoryToImageInfoEXT* pInfo)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_image, image, pInfo->dstImage);
/* MEMCPY: host bellek image'in kendi (tiled) duzeninde; layout donusumu
* yapilmaz, tile araligi ham kopyalanir. */
const bool raw_memcpy =
(pInfo->flags & VK_HOST_IMAGE_COPY_MEMCPY_BIT_EXT) != 0;
for (uint32_t r = 0; r < pInfo->regionCount; r++) {
const VkMemoryToImageCopyEXT *region = &pInfo->pRegions[r];
const uint32_t plane =
anv_image_aspect_to_plane(image, region->imageSubresource.aspectMask);
const struct isl_surf *surf = &image->planes[plane].primary_surface.isl;
const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
const unsigned cpp = fmtl->bpb / 8;
struct host_copy_map m;
VkResult res = host_copy_map_plane(device, image, plane, &m);
if (res != VK_SUCCESS)
return res;
/* Host tarafindaki satir/dilim adimlari (texel -> byte) */
const uint32_t row_len_texels = region->memoryRowLength ?
region->memoryRowLength : region->imageExtent.width;
const uint32_t img_h_texels = region->memoryImageHeight ?
region->memoryImageHeight : region->imageExtent.height;
const uint32_t host_pitch_B = DIV_ROUND_UP(row_len_texels, fmtl->bw) * cpp;
const uint32_t host_slice_B =
host_pitch_B * DIV_ROUND_UP(img_h_texels, fmtl->bh);
const uint32_t layer_count =
vk_image_subresource_layer_count(&image->vk, &region->imageSubresource);
const uint32_t slices = MAX2(layer_count, region->imageExtent.depth);
for (uint32_t s = 0; s < slices; s++) {
const uint32_t slice_idx =
(surf->dim == ISL_SURF_DIM_3D) ?
(region->imageOffset.z + s) :
(region->imageSubresource.baseArrayLayer + s);
uint32_t x1_B, x2_B, y1_el, y2_el;
host_copy_tile_extents(surf, &region->imageOffset,
&region->imageExtent,
region->imageSubresource.mipLevel,
slice_idx,
&x1_B, &x2_B, &y1_el, &y2_el);
const uint8_t *host_slice =
(const uint8_t *)region->pHostPointer + s * host_slice_B;
const uint32_t rows = y2_el - y1_el;
const uint32_t row_bytes = x2_B - x1_B;
/* MEMCPY hizli yolu: slice benzersiz tile'lara denk geliyorsa host
* bellek (zaten tiled) dogrudan image BO'ya ham kopyalanir. */
if (raw_memcpy) {
uint64_t start_tile_B, end_tile_B;
if (isl_surf_image_has_unique_tiles(
surf, region->imageSubresource.mipLevel,
slice_idx, 1, &start_tile_B, &end_tile_B)) {
memcpy((uint8_t *)m.map + m.addr.offset + start_tile_B,
host_slice, end_tile_B - start_tile_B);
continue;
}
}
if (surf->tiling == ISL_TILING_LINEAR) {
uint8_t *dst = (uint8_t *)m.map + m.addr.offset;
for (uint32_t y = 0; y < rows; y++) {
memcpy(dst + (y1_el + y) * surf->row_pitch_B + x1_B,
host_slice + y * host_pitch_B,
row_bytes);
}
continue;
}
const uint32_t bounce_pitch = align(surf->row_pitch_B, 16);
uint8_t *bounce;
void *bounce_base =
host_copy_alloc_bounce(bounce_pitch, rows, x1_B, &bounce);
if (bounce_base == NULL) {
host_copy_unmap_plane(device, &m);
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
/* Once host -> bounce, sonra bounce -> tiled image */
for (uint32_t y = 0; y < rows; y++) {
memcpy(bounce + y * bounce_pitch,
host_slice + y * host_pitch_B,
row_bytes);
}
isl_memcpy_linear_to_tiled(x1_B, x2_B, y1_el, y2_el,
(char *)m.map + m.addr.offset, /* dst: tiled */
(const char *)bounce, /* src: linear */
surf->row_pitch_B, /* dst_pitch */
bounce_pitch, /* src_pitch */
device->isl_dev.has_bit6_swizzling,
surf->tiling, ISL_MEMCPY);
os_free_aligned(bounce_base);
}
host_copy_unmap_plane(device, &m);
}
return VK_SUCCESS;
}
VkResult anv_CopyImageToMemoryEXT(
VkDevice _device,
const VkCopyImageToMemoryInfoEXT* pInfo)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_image, image, pInfo->srcImage);
/* MEMCPY: bkz. anv_CopyMemoryToImageEXT */
const bool raw_memcpy =
(pInfo->flags & VK_HOST_IMAGE_COPY_MEMCPY_BIT_EXT) != 0;
for (uint32_t r = 0; r < pInfo->regionCount; r++) {
const VkImageToMemoryCopyEXT *region = &pInfo->pRegions[r];
const uint32_t plane =
anv_image_aspect_to_plane(image, region->imageSubresource.aspectMask);
const struct isl_surf *surf = &image->planes[plane].primary_surface.isl;
const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
const unsigned cpp = fmtl->bpb / 8;
struct host_copy_map m;
VkResult res = host_copy_map_plane(device, image, plane, &m);
if (res != VK_SUCCESS)
return res;
const uint32_t row_len_texels = region->memoryRowLength ?
region->memoryRowLength : region->imageExtent.width;
const uint32_t img_h_texels = region->memoryImageHeight ?
region->memoryImageHeight : region->imageExtent.height;
const uint32_t host_pitch_B = DIV_ROUND_UP(row_len_texels, fmtl->bw) * cpp;
const uint32_t host_slice_B =
host_pitch_B * DIV_ROUND_UP(img_h_texels, fmtl->bh);
const uint32_t layer_count =
vk_image_subresource_layer_count(&image->vk, &region->imageSubresource);
const uint32_t slices = MAX2(layer_count, region->imageExtent.depth);
for (uint32_t s = 0; s < slices; s++) {
const uint32_t slice_idx =
(surf->dim == ISL_SURF_DIM_3D) ?
(region->imageOffset.z + s) :
(region->imageSubresource.baseArrayLayer + s);
uint32_t x1_B, x2_B, y1_el, y2_el;
host_copy_tile_extents(surf, &region->imageOffset,
&region->imageExtent,
region->imageSubresource.mipLevel,
slice_idx,
&x1_B, &x2_B, &y1_el, &y2_el);
uint8_t *host_slice =
(uint8_t *)region->pHostPointer + s * host_slice_B;
const uint32_t rows = y2_el - y1_el;
const uint32_t row_bytes = x2_B - x1_B;
/* MEMCPY hizli yolu: image BO'dan (tiled) host bellege ham kopya. */
if (raw_memcpy) {
uint64_t start_tile_B, end_tile_B;
if (isl_surf_image_has_unique_tiles(
surf, region->imageSubresource.mipLevel,
slice_idx, 1, &start_tile_B, &end_tile_B)) {
memcpy(host_slice,
(const uint8_t *)m.map + m.addr.offset + start_tile_B,
end_tile_B - start_tile_B);
continue;
}
}
if (surf->tiling == ISL_TILING_LINEAR) {
const uint8_t *src = (const uint8_t *)m.map + m.addr.offset;
for (uint32_t y = 0; y < rows; y++) {
memcpy(host_slice + y * host_pitch_B,
src + (y1_el + y) * surf->row_pitch_B + x1_B,
row_bytes);
}
continue;
}
const uint32_t bounce_pitch = align(surf->row_pitch_B, 16);
uint8_t *bounce;
void *bounce_base =
host_copy_alloc_bounce(bounce_pitch, rows, x1_B, &bounce);
if (bounce_base == NULL) {
host_copy_unmap_plane(device, &m);
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
/* Once tiled image -> bounce, sonra bounce -> host */
isl_memcpy_tiled_to_linear(x1_B, x2_B, y1_el, y2_el,
(char *)bounce, /* dst: linear */
(const char *)m.map + m.addr.offset, /* src: tiled */
bounce_pitch, /* dst_pitch */
surf->row_pitch_B, /* src_pitch */
device->isl_dev.has_bit6_swizzling,
surf->tiling, ISL_MEMCPY);
for (uint32_t y = 0; y < rows; y++) {
memcpy(host_slice + y * host_pitch_B,
bounce + y * bounce_pitch,
row_bytes);
}
os_free_aligned(bounce_base);
}
host_copy_unmap_plane(device, &m);
}
return VK_SUCCESS;
}
VkResult anv_CopyImageToImageEXT(
VkDevice _device,
const VkCopyImageToImageInfoEXT* pInfo)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_image, src_image, pInfo->srcImage);
for (uint32_t r = 0; r < pInfo->regionCount; r++) {
const VkImageCopy2 *region = &pInfo->pRegions[r];
const uint32_t plane =
anv_image_aspect_to_plane(src_image,
region->srcSubresource.aspectMask);
const struct isl_surf *surf =
&src_image->planes[plane].primary_surface.isl;
const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
const unsigned cpp = fmtl->bpb / 8;
/* Ara buffer'in duzeni, iki entrypoint'in memoryRowLength == 0
* durumunda kullandigi duzenle birebir ayni olmali.
*/
const uint32_t w_el = DIV_ROUND_UP(region->extent.width, fmtl->bw);
const uint32_t h_el = DIV_ROUND_UP(region->extent.height, fmtl->bh);
const uint32_t pitch = w_el * cpp;
const uint32_t layers =
vk_image_subresource_layer_count(&src_image->vk,
&region->srcSubresource);
const uint32_t slices = MAX2(layers, region->extent.depth);
const size_t tmp_size = (size_t)pitch * h_el * slices;
void *tmp = os_malloc_aligned(tmp_size, 16);
if (tmp == NULL)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
const VkImageToMemoryCopyEXT out_region = {
.sType = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT,
.pHostPointer = tmp,
.memoryRowLength = 0,
.memoryImageHeight = 0,
.imageSubresource = region->srcSubresource,
.imageOffset = region->srcOffset,
.imageExtent = region->extent,
};
/* Ara buffer bizim sectigimiz sikisik linear duzende; MEMCPY (tiled ham
* kopya) bayragini ic transferlere tasimayiz, aksi halde tiled boyut
* linear boyutlu tmp'yi tasirir. */
const VkCopyImageToMemoryInfoEXT out_info = {
.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
.flags = 0,
.srcImage = pInfo->srcImage,
.srcImageLayout = pInfo->srcImageLayout,
.regionCount = 1,
.pRegions = &out_region,
};
VkResult res = anv_CopyImageToMemoryEXT(_device, &out_info);
if (res != VK_SUCCESS) {
os_free_aligned(tmp);
return res;
}
const VkMemoryToImageCopyEXT in_region = {
.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
.pHostPointer = tmp,
.memoryRowLength = 0,
.memoryImageHeight = 0,
.imageSubresource = region->dstSubresource,
.imageOffset = region->dstOffset,
.imageExtent = region->extent,
};
const VkCopyMemoryToImageInfoEXT in_info = {
.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
.flags = 0,
.dstImage = pInfo->dstImage,
.dstImageLayout = pInfo->dstImageLayout,
.regionCount = 1,
.pRegions = &in_region,
};
res = anv_CopyMemoryToImageEXT(_device, &in_info);
os_free_aligned(tmp);
if (res != VK_SUCCESS)
return res;
}
return VK_SUCCESS;
}
VkResult anv_TransitionImageLayoutEXT(
VkDevice device,
uint32_t transitionCount,
const VkHostImageLayoutTransitionInfoEXT* pTransitions)
{
/* Host copy icin yalnizca aux surface'i olmayan layout'lar
* (VK_IMAGE_LAYOUT_GENERAL) raporlaniyor, dolayisiyla burada
* yapilacak bir is yok.
*/
return VK_SUCCESS;
}
+43 -6
View File
@@ -1926,7 +1926,8 @@ VkResult anv_BindImageMemory2(
}
static void
anv_get_image_subresource_layout(const struct anv_image *image,
anv_get_image_subresource_layout(struct anv_device *device,
const struct anv_image *image,
const VkImageSubresource2KHR *subresource,
VkSubresourceLayout2KHR *layout)
{
@@ -2012,14 +2013,49 @@ anv_get_image_subresource_layout(const struct anv_image *image,
} else {
layout->subresourceLayout.size = surface->memory_range.size;
}
/* VK_EXT_host_image_copy: MEMCPY kopyalari icin uygulamanin ayirmasi
* gereken host bellek boyutu. Benzersiz tile'lara denk gelen subresource
* icin ham tile araligi; aksi halde linear yerlesimin boyutu. */
VkSubresourceHostMemcpySizeEXT *host_memcpy_size =
vk_find_struct(layout->pNext, SUBRESOURCE_HOST_MEMCPY_SIZE_EXT);
if (host_memcpy_size) {
const struct isl_surf *isl_surf = &surface->isl;
const uint32_t level = subresource->imageSubresource.mipLevel;
const uint32_t layer = subresource->imageSubresource.arrayLayer;
const uint32_t layers = u_minify(isl_surf->logical_level0_px.d, level);
uint64_t start_tile_B, end_tile_B;
if (isl_surf_image_has_unique_tiles(isl_surf, level, layer, layers,
&start_tile_B, &end_tile_B)) {
host_memcpy_size->size = end_tile_B - start_tile_B;
} else {
/* Ham memcpy mumkun degilse veriyi linear duzende sakliyoruz. */
struct isl_surf lin_surf;
ASSERTED bool ok =
isl_surf_init(&device->isl_dev, &lin_surf,
.dim = isl_surf->dim,
.format = isl_surf->format,
.width = u_minify(isl_surf->logical_level0_px.w, level),
.height = u_minify(isl_surf->logical_level0_px.h, level),
.depth = u_minify(isl_surf->logical_level0_px.d, level),
.array_len = 1,
.levels = 1,
.samples = isl_surf->samples,
.tiling_flags = ISL_TILING_LINEAR_BIT);
assert(ok);
host_memcpy_size->size = lin_surf.size_B;
}
}
}
void anv_GetImageSubresourceLayout(
VkDevice device,
VkDevice _device,
VkImage _image,
const VkImageSubresource* pSubresource,
VkSubresourceLayout* pLayout)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_image, image, _image);
VkImageSubresource2KHR subresource = {
@@ -2029,7 +2065,7 @@ void anv_GetImageSubresourceLayout(
VkSubresourceLayout2KHR layout = {
.sType = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR
};
anv_get_image_subresource_layout(image, &subresource, &layout);
anv_get_image_subresource_layout(device, image, &subresource, &layout);
*pLayout = layout.subresourceLayout;
}
@@ -2048,18 +2084,19 @@ void anv_GetDeviceImageSubresourceLayoutKHR(
return;
}
anv_get_image_subresource_layout(&image, pInfo->pSubresource, pLayout);
anv_get_image_subresource_layout(device, &image, pInfo->pSubresource, pLayout);
}
void anv_GetImageSubresourceLayout2KHR(
VkDevice device,
VkDevice _device,
VkImage _image,
const VkImageSubresource2KHR* pSubresource,
VkSubresourceLayout2KHR* pLayout)
{
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_image, image, _image);
anv_get_image_subresource_layout(image, pSubresource, pLayout);
anv_get_image_subresource_layout(device, image, pSubresource, pLayout);
}
/**
+64 -15
View File
@@ -531,6 +531,8 @@ anv_pipeline_lower_nir(struct anv_pipeline *pipeline,
.lower_stores = true,
.lower_atomics = true,
.lower_get_size = true,
.robust_image_access =
stage->key.base.robust_flags & ELK_ROBUSTNESS_IMAGE,
});
NIR_PASS(_, nir, nir_lower_explicit_io, nir_var_mem_global,
@@ -1058,15 +1060,50 @@ anv_pipeline_add_executables(struct anv_pipeline *pipeline,
}
}
/* VK_EXT_pipeline_robustness: derive the compiler's UBO/SSBO robustness bits
* from a per-pipeline/-stage robustness state. The elk backend only knows
* about UBO and SSBO robustness; image and vertex-input robustness are handled
* by the hardware (always robust on Intel), which is a spec-legal superset of
* any requested behavior. */
static enum elk_robustness_flags
anv_device_get_robust_flags(const struct anv_device *device)
anv_get_robust_flags(const struct vk_pipeline_robustness_state *rs)
{
return device->robust_buffer_access ?
(ELK_ROBUSTNESS_UBO | ELK_ROBUSTNESS_SSBO) : 0;
/* A null descriptor is realized through the same bounds-checked address
* format on Gen7, so it also requires the robust flag (matching the old
* robust_buffer_access = robustBufferAccess || nullDescriptor coupling). */
return
(((rs->storage_buffers !=
VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT) ||
rs->null_storage_buffer_descriptor) ? ELK_ROBUSTNESS_SSBO : 0) |
(((rs->uniform_buffers !=
VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT) ||
rs->null_uniform_buffer_descriptor) ? ELK_ROBUSTNESS_UBO : 0);
}
/* Resolve the effective robustness for one shader stage, honoring any
* VkPipelineRobustnessCreateInfoEXT on the pipeline or the stage, falling back
* to the device default. */
static enum elk_robustness_flags
anv_stage_get_robust_flags(const struct anv_device *device,
const void *pipeline_pNext,
const void *stage_pNext)
{
struct vk_pipeline_robustness_state rs;
vk_pipeline_robustness_state_fill(&device->vk.robustness_state, &rs,
pipeline_pNext, stage_pNext);
/* Image robustness has no per-pipeline knob: nullDescriptor covers image
* descriptors device-wide, and gfx7 needs shader-side bounds checking to
* honour it (the null surface still has one live texel).
*/
return anv_get_robust_flags(&rs) |
(device->vk.enabled_features.nullDescriptor ?
ELK_ROBUSTNESS_IMAGE : 0);
}
static void
anv_graphics_pipeline_init_keys(struct anv_graphics_pipeline *pipeline,
const void *pipeline_pNext,
const struct vk_graphics_pipeline_state *state,
struct anv_pipeline_stage *stages)
{
@@ -1080,7 +1117,9 @@ anv_graphics_pipeline_init_keys(struct anv_graphics_pipeline *pipeline,
NULL, stages[s].shader_blake3);
const struct anv_device *device = pipeline->base.device;
enum elk_robustness_flags robust_flags = anv_device_get_robust_flags(device);
enum elk_robustness_flags robust_flags =
anv_stage_get_robust_flags(device, pipeline_pNext,
stages[s].info->pNext);
switch (stages[s].stage) {
case MESA_SHADER_VERTEX:
populate_vs_prog_key(device,
@@ -1265,7 +1304,7 @@ anv_graphics_pipeline_compile(struct anv_graphics_pipeline *pipeline,
stages[stage].info = &info->pStages[i];
}
anv_graphics_pipeline_init_keys(pipeline, state, stages);
anv_graphics_pipeline_init_keys(pipeline, info->pNext, state, stages);
unsigned char blake3[BLAKE3_KEY_LEN];
anv_pipeline_hash_graphics(pipeline, layout, stages, blake3);
@@ -1496,7 +1535,8 @@ anv_pipeline_compile_cs(struct anv_compute_pipeline *pipeline,
struct anv_shader_bin *bin = NULL;
populate_cs_prog_key(device,
anv_device_get_robust_flags(device),
anv_stage_get_robust_flags(device, info->pNext,
info->stage.pNext),
&stage.key.cs);
ANV_FROM_HANDLE(anv_pipeline_layout, layout, info->layout);
@@ -1796,16 +1836,25 @@ anv_graphics_pipeline_init(struct anv_graphics_pipeline *pipeline,
const uint64_t inputs_read = get_vs_prog_data(pipeline)->inputs_read;
u_foreach_bit(a, state->vi->attributes_valid) {
if (inputs_read & BITFIELD64_BIT(VERT_ATTRIB_GENERIC0 + a))
pipeline->vb_used |= BITFIELD64_BIT(state->vi->attributes[a].binding);
}
/* With VK_EXT_vertex_input_dynamic_state the vertex input is not known
* until draw time, so state->vi is NULL and all of this is recomputed from
* the dynamic state in genX(cmd_buffer_flush_vertex_input).
*/
pipeline->dynamic_vertex_input =
BITSET_TEST(state->dynamic, MESA_VK_DYNAMIC_VI);
u_foreach_bit(b, state->vi->bindings_valid) {
pipeline->vb[b].stride = state->vi->bindings[b].stride;
pipeline->vb[b].instanced = state->vi->bindings[b].input_rate ==
VK_VERTEX_INPUT_RATE_INSTANCE;
pipeline->vb[b].instance_divisor = state->vi->bindings[b].divisor;
if (state->vi != NULL) {
u_foreach_bit(a, state->vi->attributes_valid) {
if (inputs_read & BITFIELD64_BIT(VERT_ATTRIB_GENERIC0 + a))
pipeline->vb_used |= BITFIELD64_BIT(state->vi->attributes[a].binding);
}
u_foreach_bit(b, state->vi->bindings_valid) {
pipeline->vb[b].stride = state->vi->bindings[b].stride;
pipeline->vb[b].instanced = state->vi->bindings[b].input_rate ==
VK_VERTEX_INPUT_RATE_INSTANCE;
pipeline->vb[b].instance_divisor = state->vi->bindings[b].divisor;
}
}
pipeline->instance_multiplier = 1;
+47 -4
View File
@@ -103,7 +103,6 @@ struct anv_buffer_view;
struct anv_image;
struct anv_image_view;
struct anv_instance;
struct intel_perf_config;
struct intel_perf_counter_pass;
struct intel_perf_query_result;
@@ -806,7 +805,7 @@ struct anv_queue_family {
enum intel_engine_class engine_class;
};
#define ANV_MAX_QUEUE_FAMILIES 3
#define ANV_MAX_QUEUE_FAMILIES 4
struct anv_memory_type {
/* Standard bits passed on to the client */
@@ -944,6 +943,7 @@ struct anv_instance {
enum anv_debug {
ANV_DEBUG_VIDEO_DECODE = BITFIELD_BIT(0),
ANV_DEBUG_VIDEO_DEBUG = BITFIELD_BIT(1),
ANV_DEBUG_VIDEO_ENCODE = BITFIELD_BIT(2),
};
extern enum anv_debug anv_debug;
@@ -1872,7 +1872,7 @@ anv_descriptor_set_write_buffer_view(struct anv_device *device,
uint32_t binding,
uint32_t element);
void
VkResult
anv_descriptor_set_write_buffer(struct anv_device *device,
struct anv_descriptor_set *set,
struct anv_state_stream *alloc_stream,
@@ -1891,7 +1891,7 @@ anv_descriptor_set_write_inline_uniform_data(struct anv_device *device,
size_t offset,
size_t size);
void
VkResult
anv_descriptor_set_write_template(struct anv_device *device,
struct anv_descriptor_set *set,
struct anv_state_stream *alloc_stream,
@@ -2079,6 +2079,14 @@ anv_pipe_flush_bits_for_access_flags(struct anv_device *device,
*/
pipe_bits |= ANV_PIPE_HDC_PIPELINE_FLUSH_BIT;
pipe_bits |= ANV_PIPE_UNTYPED_DATAPORT_CACHE_FLUSH_BIT;
/* On gfx7, typed surface writes (image stores) are serviced by the
* render cache rather than the data cache, so it has to be flushed
* as well or the writes stay invisible to subsequent operations.
* This only shows up from the fragment stage, where the render cache
* is actually in use.
*/
if (device->info->ver <= 7)
pipe_bits |= ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT;
break;
case VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT:
/* We're transitioning a buffer that was previously used as render
@@ -2481,6 +2489,13 @@ struct anv_cmd_graphics_state {
struct vk_sample_locations_state sample_locations;
/** Backing storage for vk_dynamic_graphics_state::vi
*
* The common runtime requires the driver to provide this whenever
* VK_EXT_vertex_input_dynamic_state is supported.
*/
struct vk_vertex_input_state vertex_input;
bool has_uint_rt;
};
@@ -2541,6 +2556,11 @@ struct anv_cmd_state {
bool hiz_enabled;
bool conditional_render_enabled;
/* Gen7: buffer address + inverted flag, re-evaluated before every draw
* since IVB has no GPR to latch a precomputed result like Gfx7.5+ does.
*/
struct anv_address conditional_render_value_addr;
bool conditional_render_inverted;
/**
* Last rendering scale argument provided to
@@ -2651,6 +2671,12 @@ struct anv_cmd_buffer {
struct {
struct anv_video_session *vid;
struct anv_video_session_params *params;
/* ENCODE — destination for VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR.
* Carried from CmdBeginQueryIndexedEXT to CmdEncodeVideoKHR, since only
* the encode command knows the final bitstream offset/size and does the
* actual write. NULL bo means no active feedback query. */
struct anv_address encode_feedback_query_addr;
} video;
};
@@ -2874,6 +2900,13 @@ struct anv_graphics_pipeline {
bool force_fragment_thread_dispatch;
bool negative_one_to_one;
/** True if VK_DYNAMIC_STATE_VERTEX_INPUT_EXT is in use.
*
* When set, vb_used and vb[] below are not filled in at pipeline-creation
* time; the vertex input is emitted from the command buffer instead.
*/
bool dynamic_vertex_input;
uint32_t vb_used;
struct anv_pipeline_vertex_binding {
uint32_t stride;
@@ -3795,6 +3828,16 @@ enum {
ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE,
ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH,
ANV_VID_MEM_H264_MPR_ROW_SCRATCH,
/* Encode-only scratch buffers (MB status, MFX_AVC_DIRECTMODE_STATE MV
* buffers). Exposed as separate memoryBindIndex values and bound through
* the same path as decode. */
ANV_VID_MEM_H264_ENC_MB_STATUS,
ANV_VID_MEM_H264_ENC_DIRECT_MV_TOP,
ANV_VID_MEM_H264_ENC_DIRECT_MV_BOTTOM,
/* Input motion-vector data read by the PAK for inter/P macroblocks
* (MFX_IND_OBJ_BASE_ADDR_STATE MFXIndirectMVObjectAddress). Kept separate
* from the DIRECTMODE write buffers so the PAK does not clobber it. */
ANV_VID_MEM_H264_ENC_INPUT_MV,
ANV_VID_MEM_H264_MAX,
};
+252 -39
View File
@@ -28,6 +28,7 @@
#include "vk_common_entrypoints.h"
#include "vk_video/vulkan_video_codecs_common.h"
#include "vk_video/vulkan_video_codec_h264std.h"
#include "vk_video/vulkan_video_codec_h264std_encode.h"
VkResult
anv_CreateVideoSessionKHR(VkDevice _device,
@@ -114,25 +115,59 @@ anv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
VkVideoCapabilitiesKHR
*pCapabilities)
{
if (pVideoProfile->videoCodecOperation != VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) {
const bool is_encode =
pVideoProfile->videoCodecOperation == VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR;
if (pVideoProfile->videoCodecOperation != VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR &&
!is_encode) {
return VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR;
}
const VkVideoDecodeH264ProfileInfoKHR *h264_profile =
vk_find_struct_const(pVideoProfile->pNext, VIDEO_DECODE_H264_PROFILE_INFO_KHR);
if (h264_profile) {
switch (h264_profile->stdProfileIdc) {
case STD_VIDEO_H264_PROFILE_IDC_BASELINE:
case STD_VIDEO_H264_PROFILE_IDC_MAIN:
case STD_VIDEO_H264_PROFILE_IDC_HIGH:
break;
default:
return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR;
if (pVideoProfile->chromaSubsampling != VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR ||
pVideoProfile->lumaBitDepth != VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR ||
pVideoProfile->chromaBitDepth != VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR)
return VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR;
if (!is_encode) {
const VkVideoDecodeH264ProfileInfoKHR *h264_profile =
vk_find_struct_const(pVideoProfile->pNext, VIDEO_DECODE_H264_PROFILE_INFO_KHR);
if (h264_profile) {
switch (h264_profile->stdProfileIdc) {
case STD_VIDEO_H264_PROFILE_IDC_BASELINE:
case STD_VIDEO_H264_PROFILE_IDC_MAIN:
case STD_VIDEO_H264_PROFILE_IDC_HIGH:
break;
default:
return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR;
}
}
} else {
/* Baseline and Main are supported. Main is accepted so that CABAC
* (entropy_coding_mode_flag == 1, forbidden in Baseline) can be selected;
* the PAK performs the entropy coding. Main's inter-prediction features
* (B slices) are still not emitted — only I frames are produced. High is
* rejected (8x8 transform / scaling lists not emitted). */
const VkVideoEncodeH264ProfileInfoKHR *h264_profile =
vk_find_struct_const(pVideoProfile->pNext, VIDEO_ENCODE_H264_PROFILE_INFO_KHR);
if (h264_profile) {
switch (h264_profile->stdProfileIdc) {
case STD_VIDEO_H264_PROFILE_IDC_BASELINE:
case STD_VIDEO_H264_PROFILE_IDC_MAIN:
break;
default:
return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR;
}
}
}
pCapabilities->minBitstreamBufferOffsetAlignment = 32;
pCapabilities->minBitstreamBufferSizeAlignment = 32;
if (is_encode) {
pCapabilities->minBitstreamBufferOffsetAlignment = 4096;
pCapabilities->minBitstreamBufferSizeAlignment = 4096;
} else {
pCapabilities->minBitstreamBufferOffsetAlignment = 32;
pCapabilities->minBitstreamBufferSizeAlignment = 32;
}
pCapabilities->pictureAccessGranularity.width = ANV_MB_WIDTH;
pCapabilities->pictureAccessGranularity.height = ANV_MB_HEIGHT;
pCapabilities->minCodedExtent.width = ANV_MB_WIDTH;
@@ -142,29 +177,87 @@ anv_GetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice,
pCapabilities->flags =
VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR;
struct VkVideoDecodeCapabilitiesKHR *dec_caps =
(struct VkVideoDecodeCapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_CAPABILITIES_KHR);
if (dec_caps)
dec_caps->flags =
VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR;
if (!is_encode) {
struct VkVideoDecodeCapabilitiesKHR *dec_caps =
(struct VkVideoDecodeCapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_DECODE_CAPABILITIES_KHR);
if (dec_caps)
dec_caps->flags =
VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR;
struct VkVideoDecodeH264CapabilitiesKHR *ext =
(struct VkVideoDecodeH264CapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext,
VIDEO_DECODE_H264_CAPABILITIES_KHR);
pCapabilities->maxDpbSlots = 16;
pCapabilities->maxActiveReferencePictures = 16;
struct VkVideoDecodeH264CapabilitiesKHR *ext =
(struct VkVideoDecodeH264CapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext,
VIDEO_DECODE_H264_CAPABILITIES_KHR);
pCapabilities->maxDpbSlots = 16;
pCapabilities->maxActiveReferencePictures = 16;
if (ext) {
ext->fieldOffsetGranularity.x = 0;
ext->fieldOffsetGranularity.y = 0;
ext->maxLevelIdc = 51;
if (ext) {
ext->fieldOffsetGranularity.x = 0;
ext->fieldOffsetGranularity.y = 0;
ext->maxLevelIdc = 51;
}
strcpy(pCapabilities->stdHeaderVersion.extensionName,
VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME);
pCapabilities->stdHeaderVersion.specVersion =
VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION;
} else {
/* Limits reflecting what the encoder emits: I and P frames, CQP, single
* reference. P frames use one reference (the previous reconstructed
* frame) plus the current setup slot, so two DPB slots and one active
* reference. B frames and multi-reference are not implemented. */
pCapabilities->maxDpbSlots = 2;
pCapabilities->maxActiveReferencePictures = 1;
struct VkVideoEncodeCapabilitiesKHR *enc_caps =
(struct VkVideoEncodeCapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_CAPABILITIES_KHR);
if (enc_caps) {
enc_caps->flags = 0;
/* Constant QP only; no CBR/VBR rate control. */
enc_caps->rateControlModes =
VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR;
enc_caps->maxRateControlLayers = 1;
enc_caps->maxBitrate = 0;
enc_caps->maxQualityLevels = 1;
enc_caps->encodeInputPictureGranularity.width = ANV_MB_WIDTH;
enc_caps->encodeInputPictureGranularity.height = ANV_MB_HEIGHT;
/* Both flags are required by the ffmpeg h264_vulkan encoder. Note
* that bytes-written currently reports the full dstBufferRange rather
* than the real encoded size; reading back the MFC bit counter is not
* yet implemented. */
enc_caps->supportedEncodeFeedbackFlags =
VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR |
VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR;
}
struct VkVideoEncodeH264CapabilitiesKHR *h264_enc_ext =
(struct VkVideoEncodeH264CapabilitiesKHR *)
vk_find_struct(pCapabilities->pNext, VIDEO_ENCODE_H264_CAPABILITIES_KHR);
if (h264_enc_ext) {
h264_enc_ext->flags =
VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_KHR;
h264_enc_ext->maxLevelIdc = STD_VIDEO_H264_LEVEL_IDC_4_1;
/* One slice per MB row at most (matches the encoder's row-granular
* slice splitting). */
h264_enc_ext->maxSliceCount = 68; /* 1088/16, covers up to 1080p */
h264_enc_ext->maxPPictureL0ReferenceCount = 1;
h264_enc_ext->maxBPictureL0ReferenceCount = 0;
h264_enc_ext->maxL1ReferenceCount = 0;
h264_enc_ext->maxTemporalLayerCount = 1;
h264_enc_ext->expectDyadicTemporalLayerPattern = VK_FALSE;
h264_enc_ext->minQp = 0;
h264_enc_ext->maxQp = 51;
h264_enc_ext->prefersGopRemainingFrames = VK_FALSE;
h264_enc_ext->requiresGopRemainingFrames = VK_FALSE;
h264_enc_ext->stdSyntaxFlags = 0;
}
strcpy(pCapabilities->stdHeaderVersion.extensionName,
VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME);
pCapabilities->stdHeaderVersion.specVersion =
VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION;
}
strcpy(pCapabilities->stdHeaderVersion.extensionName,
VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME);
pCapabilities->stdHeaderVersion.specVersion =
VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION;
return VK_SUCCESS;
}
@@ -224,6 +317,8 @@ get_h264_video_mem_size(struct anv_video_session *vid, uint32_t mem_idx)
{
uint32_t width_in_mb =
align(vid->vk.max_coded.width, ANV_MB_WIDTH) / ANV_MB_WIDTH;
uint32_t height_in_mb =
align(vid->vk.max_coded.height, ANV_MB_HEIGHT) / ANV_MB_HEIGHT;
switch (mem_idx) {
case ANV_VID_MEM_H264_INTRA_ROW_STORE:
@@ -238,6 +333,15 @@ get_h264_video_mem_size(struct anv_video_session *vid, uint32_t mem_idx)
case ANV_VID_MEM_H264_MPR_ROW_SCRATCH:
/* mpr row scratch is width in macroblocks * 64 * 2 */
return width_in_mb * 64 * 2;
/* Encode scratch buffer sizes, matching gen6_mfc_init (VA-API). */
case ANV_VID_MEM_H264_ENC_MB_STATUS:
return width_in_mb * height_in_mb * 16;
case ANV_VID_MEM_H264_ENC_DIRECT_MV_TOP:
case ANV_VID_MEM_H264_ENC_DIRECT_MV_BOTTOM:
return 68ull * width_in_mb * height_in_mb;
case ANV_VID_MEM_H264_ENC_INPUT_MV:
/* 16 4x4 motion-vector pairs (32MV) per MB, 4 bytes each = 64 bytes. */
return 64ull * width_in_mb * height_in_mb;
default:
UNREACHABLE("unknown memory");
}
@@ -247,21 +351,32 @@ static void
get_h264_video_session_mem_reqs(struct anv_video_session *vid,
VkVideoSessionMemoryRequirementsKHR *mem_reqs,
uint32_t *pVideoSessionMemoryRequirementsCount,
uint32_t memory_types)
uint32_t memory_types,
uint32_t first_mem_idx,
uint32_t count)
{
VK_OUTARRAY_MAKE_TYPED(VkVideoSessionMemoryRequirementsKHR,
out,
mem_reqs,
pVideoSessionMemoryRequirementsCount);
for (unsigned i = 0; i < ANV_VID_MEM_H264_MAX; i++) {
uint32_t bind_index = ANV_VID_MEM_H264_INTRA_ROW_STORE + i;
uint64_t size = get_h264_video_mem_size(vid, i);
for (unsigned i = 0; i < count; i++) {
uint32_t bind_index = first_mem_idx + i;
uint64_t size = get_h264_video_mem_size(vid, bind_index);
/* The row-store and direct-MV scratch buffers reach the hardware through
* MFX_PIPE_BUF_ADDR_STATE / MFX_BSP_BUF_BASE_ADDR_STATE, whose address
* fields are bits 31:6, so 64 bytes is enough. The encode input-MV buffer
* instead feeds MFX_IND_OBJ_BASE_ADDR_STATE, which stores addresses in
* bits 31:12; a base that is not 4KiB aligned would be truncated and the
* MFC would fetch its per-MB motion vectors from the wrong address. */
uint64_t alignment = bind_index == ANV_VID_MEM_H264_ENC_INPUT_MV ?
4096 : 64;
vk_outarray_append_typed(VkVideoSessionMemoryRequirementsKHR, &out, p) {
p->memoryBindIndex = bind_index;
p->memoryRequirements.size = size;
p->memoryRequirements.alignment = 64;
p->memoryRequirements.alignment = alignment;
p->memoryRequirements.memoryTypeBits = memory_types;
}
}
@@ -283,7 +398,24 @@ anv_GetVideoSessionMemoryRequirementsKHR(VkDevice _device,
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
get_h264_video_session_mem_reqs(vid, mem_reqs,
pVideoSessionMemoryRequirementsCount,
memory_types);
memory_types,
ANV_VID_MEM_H264_INTRA_ROW_STORE,
ANV_VID_MEM_H264_MPR_ROW_SCRATCH -
ANV_VID_MEM_H264_INTRA_ROW_STORE + 1);
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR:
/* A single call over the whole contiguous enum range.
* VK_OUTARRAY_MAKE_TYPED resets *count to 0 and writes from index 0 on
* every call, so two separate calls would make the second clobber the
* first, leaving some scratch buffers unbound. MPR_ROW_SCRATCH falls in
* the range and is included even though encode does not use it (a small
* unused allocation). */
get_h264_video_session_mem_reqs(vid, mem_reqs,
pVideoSessionMemoryRequirementsCount,
memory_types,
ANV_VID_MEM_H264_INTRA_ROW_STORE,
ANV_VID_MEM_H264_ENC_INPUT_MV -
ANV_VID_MEM_H264_INTRA_ROW_STORE + 1);
break;
default:
UNREACHABLE("unknown codec");
@@ -303,6 +435,87 @@ anv_UpdateVideoSessionParametersKHR(VkDevice _device,
return vk_video_session_parameters_update(&params->vk, pUpdateInfo);
}
/* Required entry point for VK_KHR_video_encode_queue. Emits the SPS/PPS RBSP
* (start code and NAL header included) using the common
* vk_video_encode_h264_sps/pps() helpers; the H.264-only reduction of the
* mainline anv implementation. */
VkResult
anv_GetEncodedVideoSessionParametersKHR(VkDevice _device,
const VkVideoEncodeSessionParametersGetInfoKHR *pVideoSessionParametersInfo,
VkVideoEncodeSessionParametersFeedbackInfoKHR *pFeedbackInfo,
size_t *pDataSize,
void *pData)
{
ANV_FROM_HANDLE(anv_video_session_params, params,
pVideoSessionParametersInfo->videoSessionParameters);
size_t total_size = 0;
size_t size_limit = pData ? *pDataSize : 0;
if (params->vk.op == VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR) {
const struct VkVideoEncodeH264SessionParametersGetInfoKHR *h264_get_info =
vk_find_struct_const(pVideoSessionParametersInfo->pNext,
VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR);
size_t sps_size = 0, pps_size = 0;
if (h264_get_info->writeStdSPS) {
for (unsigned i = 0; i < params->vk.h264_enc.h264_sps_count; i++)
if (params->vk.h264_enc.h264_sps[i].base.seq_parameter_set_id == h264_get_info->stdSPSId)
vk_video_encode_h264_sps(&params->vk.h264_enc.h264_sps[i].base,
size_limit, &sps_size, pData);
}
if (h264_get_info->writeStdPPS) {
char *data_ptr = pData ? (char *)pData + sps_size : NULL;
for (unsigned i = 0; i < params->vk.h264_enc.h264_pps_count; i++)
if (params->vk.h264_enc.h264_pps[i].base.pic_parameter_set_id == h264_get_info->stdPPSId)
vk_video_encode_h264_pps(&params->vk.h264_enc.h264_pps[i].base,
params->vk.h264_enc.profile_idc == STD_VIDEO_H264_PROFILE_IDC_HIGH,
size_limit, &pps_size, data_ptr);
}
total_size = sps_size + pps_size;
}
/* The size check is done here against *pDataSize (mainline anv pattern). */
if (pData && *pDataSize < total_size) {
*pDataSize = 0;
return VK_INCOMPLETE;
}
*pDataSize = total_size;
return VK_SUCCESS;
}
/* Required entry point for VK_KHR_video_encode_queue; the H.264-only reduction
* of the mainline anv implementation. The reported values are preferred
* defaults and do not constrain what the application may request. */
VkResult
anv_GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR *pQualityLevelInfo,
VkVideoEncodeQualityLevelPropertiesKHR *pQualityLevelProperties)
{
const VkVideoProfileInfoKHR *profile = pQualityLevelInfo->pVideoProfile;
pQualityLevelProperties->preferredRateControlMode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR;
switch (profile->videoCodecOperation) {
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: {
VkVideoEncodeH264QualityLevelPropertiesKHR *ext =
vk_find_struct(pQualityLevelProperties->pNext, VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_KHR);
if (ext) {
ext->preferredIdrPeriod = 60;
ext->preferredGopFrameCount = 60;
ext->preferredConstantQp = (VkVideoEncodeH264QpKHR) { 26, 26, 26 };
ext->preferredMaxL0ReferenceCount = 0; /* no references */
ext->preferredMaxL1ReferenceCount = 0;
ext->preferredStdEntropyCodingModeFlag = false; /* Baseline: CAVLC */
}
break;
}
default:
return VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR;
}
return VK_SUCCESS;
}
static void
copy_bind(struct anv_vid_mem *dst, const VkBindVideoSessionMemoryInfoKHR *src)
{
@@ -0,0 +1,186 @@
/*
* Copyright © 2026 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.
*/
#include <stdbool.h>
#include <string.h>
#include "util/macros.h"
#include "anv_video_h264_bitstream.h"
struct anv_h264_bw {
uint8_t *buf;
uint32_t cap_bits;
uint32_t pos_bits;
bool overflow;
};
static void
bw_init(struct anv_h264_bw *bw, uint8_t *buf, uint32_t cap_bytes)
{
bw->buf = buf;
bw->cap_bits = cap_bytes * 8;
bw->pos_bits = 0;
bw->overflow = false;
memset(buf, 0, cap_bytes);
}
static void
bw_put_bit(struct anv_h264_bw *bw, unsigned bit)
{
if (bw->pos_bits >= bw->cap_bits) {
bw->overflow = true;
return;
}
if (bit)
bw->buf[bw->pos_bits >> 3] |= 1u << (7 - (bw->pos_bits & 7));
bw->pos_bits++;
}
/* u(n): most significant bit first. */
static void
bw_put_u(struct anv_h264_bw *bw, uint32_t value, unsigned n)
{
for (int i = (int)n - 1; i >= 0; i--)
bw_put_bit(bw, (value >> i) & 1);
}
/* ue(v) — Exp-Golomb, H.264 9.1. */
static void
bw_put_ue(struct anv_h264_bw *bw, uint32_t value)
{
uint32_t v = value + 1;
int leading = 0;
for (uint32_t t = v; t > 1; t >>= 1)
leading++;
for (int i = 0; i < leading; i++)
bw_put_bit(bw, 0);
bw_put_u(bw, v, leading + 1);
}
/* se(v) — H.264 9.1.1. */
static void
bw_put_se(struct anv_h264_bw *bw, int32_t value)
{
uint32_t code = value <= 0 ? (uint32_t)(-2 * (int64_t)value)
: (uint32_t)(2 * (int64_t)value - 1);
bw_put_ue(bw, code);
}
uint32_t
anv_h264_build_encode_slice_header(uint8_t *out_buf, uint32_t out_cap,
const StdVideoH264SequenceParameterSet *sps,
const StdVideoH264PictureParameterSet *pps,
const StdVideoEncodeH264PictureInfo *pic_info,
const StdVideoEncodeH264SliceHeader *slice_hdr)
{
/* Assumptions for syntax elements outside the current scope: frame_mbs_only
* (no field pictures), no weighted prediction (I slice), single slice group,
* single slice. */
if (out_cap < 32)
return 0;
struct anv_h264_bw bw;
bw_init(&bw, out_buf, out_cap);
/* Start code + NAL header (4-byte start code + 1-byte NAL header, which
* SkipEmulationByteCount = 5 accounts for). */
bw_put_u(&bw, 0x00000001, 32);
bool is_idr = pic_info->flags.IdrPicFlag;
unsigned nal_unit_type = is_idr ? 5 : 1;
unsigned nal_ref_idc = 1; /* I-frame is always a reference */
bw_put_bit(&bw, 0); /* forbidden_zero_bit */
bw_put_u(&bw, nal_ref_idc, 2);
bw_put_u(&bw, nal_unit_type, 5);
bw_put_ue(&bw, slice_hdr->first_mb_in_slice);
bw_put_ue(&bw, slice_hdr->slice_type);
bw_put_ue(&bw, pic_info->pic_parameter_set_id);
uint32_t log2_max_frame_num = sps->log2_max_frame_num_minus4 + 4;
bw_put_u(&bw, pic_info->frame_num, log2_max_frame_num);
/* Field pictures (frame_mbs_only_flag == 0) are out of scope; the
* StdVideoEncodeH264PictureInfo has no field_pic_flag. */
if (is_idr)
bw_put_ue(&bw, pic_info->idr_pic_id);
if (sps->pic_order_cnt_type == 0) {
uint32_t log2_max_poc_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
bw_put_u(&bw, (uint32_t)pic_info->PicOrderCnt, log2_max_poc_lsb);
/* delta_pic_order_cnt_bottom is never written for frame-only encode. */
} else if (sps->pic_order_cnt_type == 1 &&
!sps->flags.delta_pic_order_always_zero_flag) {
bw_put_se(&bw, pic_info->PicOrderCnt);
}
if (pps->flags.redundant_pic_cnt_present_flag)
bw_put_ue(&bw, 0);
/* P-slice reference-list syntax (H.264 7.3.3). B slices are out of scope, so
* direct_spatial_mv_pred_flag is never emitted. */
bool is_p = (slice_hdr->slice_type == STD_VIDEO_H264_SLICE_TYPE_P);
if (is_p) {
/* num_ref_idx_active_override_flag = 0: use the PPS default L0 count. */
bw_put_bit(&bw, 0);
/* ref_pic_list_modification_flag_l0 = 0: default frame_num-ordered list. */
bw_put_bit(&bw, 0);
}
/* pred_weight_table is absent (weighted_pred_flag is off). */
if (nal_ref_idc != 0) {
if (is_idr) {
bw_put_bit(&bw, pic_info->flags.no_output_of_prior_pics_flag);
bw_put_bit(&bw, pic_info->flags.long_term_reference_flag);
} else {
bw_put_bit(&bw, pic_info->flags.adaptive_ref_pic_marking_mode_flag);
if (pic_info->flags.adaptive_ref_pic_marking_mode_flag)
bw_put_ue(&bw, 0); /* memory_management_control_operation: end (0) */
}
}
/* cabac_init_idc is present only for CABAC P/SP/B slices (H.264 7.3.3), not
* for I slices. */
if (pps->flags.entropy_coding_mode_flag && is_p)
bw_put_ue(&bw, slice_hdr->cabac_init_idc);
bw_put_se(&bw, slice_hdr->slice_qp_delta);
if (pps->flags.deblocking_filter_control_present_flag) {
bw_put_ue(&bw, slice_hdr->disable_deblocking_filter_idc);
if (slice_hdr->disable_deblocking_filter_idc != 1) {
bw_put_se(&bw, slice_hdr->slice_alpha_c0_offset_div2);
bw_put_se(&bw, slice_hdr->slice_beta_offset_div2);
}
}
/* FMO (num_slice_groups_minus1 > 0) is out of scope. */
if (bw.overflow)
return 0;
return bw.pos_bits;
}
@@ -0,0 +1,47 @@
/*
* Copyright © 2026 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 ANV_VIDEO_H264_BITSTREAM_H
#define ANV_VIDEO_H264_BITSTREAM_H
#include <stdint.h>
#include "vk_video/vulkan_video_codec_h264std.h"
#include "vk_video/vulkan_video_codec_h264std_encode.h"
/* Builds a single I/IDR slice header (start code + NAL header + RBSP), the
* equivalent of VA-API's build_avc_slice_header(). Emulation-prevention bytes
* are NOT inserted here: MFX_PAK_INSERT_OBJECT does that in hardware via
* EmulationByteBitsInsertEnable / SkipEmulationByteCount, so this writer emits
* raw RBSP bits only.
*
* Returns the number of bits written (including start code and NAL header), or
* 0 if out_buf was too small. */
uint32_t
anv_h264_build_encode_slice_header(uint8_t *out_buf, uint32_t out_cap,
const StdVideoH264SequenceParameterSet *sps,
const StdVideoH264PictureParameterSet *pps,
const StdVideoEncodeH264PictureInfo *pic_info,
const StdVideoEncodeH264SliceHeader *slice_hdr);
#endif /* ANV_VIDEO_H264_BITSTREAM_H */
+155 -116
View File
@@ -22,6 +22,7 @@
* IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "util/macros.h"
@@ -143,6 +144,8 @@ anv_h264_gather_frefs(
int32_t poc_top = ri->PicOrderCnt[0];
int32_t poc_bot = ri->PicOrderCnt[1];
if (poc_top == INT32_MAX) poc_top = poc_bot;
if (poc_bot == INT32_MAX) poc_bot = poc_top;
if (parities == ANV_H264_PAR_TOP)
f.frame_poc = poc_top;
else if (parities == ANV_H264_PAR_BOTTOM)
@@ -210,6 +213,86 @@ anv_h264_sort_ltidx_asc(struct anv_h264_fref *a, int n)
}
}
static void
anv_h264_sort_poc_desc(struct anv_h264_fref *a, int n)
{
for (int i = 1; i < n; i++) {
struct anv_h264_fref v = a[i];
int j = i - 1;
while (j >= 0 && a[j].frame_poc < v.frame_poc) { a[j+1] = a[j]; j--; }
a[j+1] = v;
}
}
static void
anv_h264_sort_poc_asc(struct anv_h264_fref *a, int n)
{
for (int i = 1; i < n; i++) {
struct anv_h264_fref v = a[i];
int j = i - 1;
while (j >= 0 && a[j].frame_poc > v.frame_poc) { a[j+1] = a[j]; j--; }
a[j+1] = v;
}
}
/* 8.2.4.2.3 and 8.2.4.2.4 */
static void
anv_h264_swap_identical_l1(uint8_t *l0, uint8_t *l0b,
uint8_t *l1, uint8_t *l1b, int count)
{
if (count < 2)
return;
if (memcmp(l0, l1, ANV_H264_MAX_REF_FRAMES))
return;
if (l0b && l1b && memcmp(l0b, l1b, ANV_H264_MAX_REF_FRAMES))
return;
uint8_t t = l1[0]; l1[0] = l1[1]; l1[1] = t;
if (l1b) { t = l1b[0]; l1b[0] = l1b[1]; l1b[1] = t; }
}
/* 8.2.4.3.1 */
static void
anv_h264_ref_list_insert(uint8_t *list, uint8_t *listb, int active_count,
int refIdx, uint8_t slot, uint8_t bottom)
{
uint8_t tmp[ANV_H264_MAX_REF_FRAMES + 1];
uint8_t tmpb[ANV_H264_MAX_REF_FRAMES + 1];
if (refIdx < 0 || refIdx >= active_count ||
active_count > ANV_H264_MAX_REF_FRAMES)
return;
memcpy(tmp, list, ANV_H264_MAX_REF_FRAMES);
tmp[ANV_H264_MAX_REF_FRAMES] = ANV_H264_INVALID_SLOT;
if (listb) {
memcpy(tmpb, listb, ANV_H264_MAX_REF_FRAMES);
tmpb[ANV_H264_MAX_REF_FRAMES] = 0;
} else {
memset(tmpb, 0, sizeof(tmpb));
}
for (int k = active_count; k > refIdx; k--) {
tmp[k] = tmp[k - 1];
tmpb[k] = tmpb[k - 1];
}
tmp[refIdx] = slot;
tmpb[refIdx] = bottom;
int w = refIdx + 1;
for (int k = refIdx + 1; k <= active_count; k++) {
if (tmp[k] == slot && tmpb[k] == bottom)
continue;
tmp[w] = tmp[k];
tmpb[w] = tmpb[k];
w++;
}
memcpy(list, tmp, active_count);
if (listb)
memcpy(listb, tmpb, active_count);
}
static void
anv_h264_build_field_ref_lists(
int slice_type, int sel, int32_t cur_field_poc,
@@ -284,12 +367,17 @@ anv_h264_build_field_ref_lists(
anv_h264_emit_field_list(l0, l0b, ANV_H264_MAX_REF_FRAMES, &idx0, lt, nlt, sel);
anv_h264_emit_field_list(l1, l1b, ANV_H264_MAX_REF_FRAMES, &idx1, o1, no1, sel);
anv_h264_emit_field_list(l1, l1b, ANV_H264_MAX_REF_FRAMES, &idx1, lt, nlt, sel);
anv_h264_swap_identical_l1(l0, l0b, l1, l1b, idx1);
}
/* 8.2.4.2.1 and 8.2.4.2.3 */
static void
anv_h264_build_default_ref_list(
int slice_type,
int32_t curr_poc,
uint32_t cur_frame_num,
uint32_t MaxFrameNum,
uint32_t ref_slot_count,
const VkVideoReferenceSlotInfoKHR *ref_slots,
uint8_t list0[ANV_H264_MAX_REF_FRAMES],
@@ -301,95 +389,54 @@ anv_h264_build_default_ref_list(
if (slice_type == ANV_H264_SLICE_I || slice_type == ANV_H264_SLICE_SI)
return;
uint8_t st_slots[ANV_H264_MAX_REF_FRAMES];
int32_t st_poc[ANV_H264_MAX_REF_FRAMES];
int st_count = 0;
struct anv_h264_fref st[ANV_H264_MAX_REF_FRAMES];
struct anv_h264_fref lt[ANV_H264_MAX_REF_FRAMES];
int nst = 0, nlt = 0;
anv_h264_gather_frefs(ref_slot_count, ref_slots, cur_frame_num, MaxFrameNum,
st, &nst, lt, &nlt);
uint8_t lt_slots[ANV_H264_MAX_REF_FRAMES];
uint32_t lt_idx[ANV_H264_MAX_REF_FRAMES];
int lt_count = 0;
for (uint32_t i = 0; i < ref_slot_count; i++) {
const VkVideoDecodeH264DpbSlotInfoKHR *dpb =
vk_find_struct_const(ref_slots[i].pNext,
VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR);
if (!dpb) continue;
const StdVideoDecodeH264ReferenceInfo *ri = dpb->pStdReferenceInfo;
if (!ri) continue;
int slot = ref_slots[i].slotIndex;
if (ri->flags.used_for_long_term_reference) {
lt_slots[lt_count] = (uint8_t)slot;
lt_idx[lt_count] = ri->FrameNum;
lt_count++;
} else {
st_slots[st_count] = (uint8_t)slot;
st_poc[st_count] = ri->PicOrderCnt[0];
st_count++;
}
}
for (int i = 1; i < st_count; i++) {
uint8_t si = st_slots[i]; int32_t pi = st_poc[i];
int j = i - 1;
while (j >= 0 && st_poc[j] < pi) {
st_slots[j+1] = st_slots[j]; st_poc[j+1] = st_poc[j]; j--;
}
st_slots[j+1] = si; st_poc[j+1] = pi;
}
for (int i = 1; i < lt_count; i++) {
uint8_t si = lt_slots[i]; uint32_t li = lt_idx[i];
int j = i - 1;
while (j >= 0 && lt_idx[j] > li) {
lt_slots[j+1] = lt_slots[j]; lt_idx[j+1] = lt_idx[j]; j--;
}
lt_slots[j+1] = si; lt_idx[j+1] = li;
}
anv_h264_sort_ltidx_asc(lt, nlt);
if (slice_type == ANV_H264_SLICE_P || slice_type == ANV_H264_SLICE_SP) {
/* 8.2.4.2.1 */
anv_h264_sort_fnwrap_desc(st, nst);
int p = 0;
for (int i = 0; i < st_count && p < ANV_H264_MAX_REF_FRAMES; i++)
list0[p++] = st_slots[i];
for (int i = 0; i < lt_count && p < ANV_H264_MAX_REF_FRAMES; i++)
list0[p++] = lt_slots[i];
for (int i = 0; i < nst && p < ANV_H264_MAX_REF_FRAMES; i++)
list0[p++] = st[i].slot;
for (int i = 0; i < nlt && p < ANV_H264_MAX_REF_FRAMES; i++)
list0[p++] = lt[i].slot;
return;
}
uint8_t past_slots[ANV_H264_MAX_REF_FRAMES];
int32_t past_poc[ANV_H264_MAX_REF_FRAMES];
int past_cnt = 0;
uint8_t fut_slots[ANV_H264_MAX_REF_FRAMES];
int32_t fut_poc[ANV_H264_MAX_REF_FRAMES];
int fut_cnt = 0;
struct anv_h264_fref past[ANV_H264_MAX_REF_FRAMES];
struct anv_h264_fref fut[ANV_H264_MAX_REF_FRAMES];
int past_cnt = 0, fut_cnt = 0;
for (int i = 0; i < st_count; i++) {
if (st_poc[i] < curr_poc) {
past_slots[past_cnt] = st_slots[i];
past_poc[past_cnt++] = st_poc[i];
}
for (int i = 0; i < nst; i++) {
if (st[i].frame_poc < curr_poc)
past[past_cnt++] = st[i];
else
fut[fut_cnt++] = st[i];
}
for (int i = st_count - 1; i >= 0; i--) {
if (st_poc[i] >= curr_poc) {
fut_slots[fut_cnt] = st_slots[i];
fut_poc[fut_cnt++] = st_poc[i];
}
}
(void)past_poc; (void)fut_poc;
anv_h264_sort_poc_desc(past, past_cnt);
anv_h264_sort_poc_asc(fut, fut_cnt);
int p0 = 0, p1 = 0;
for (int i = 0; i < past_cnt && p0 < ANV_H264_MAX_REF_FRAMES; i++)
list0[p0++] = past_slots[i];
list0[p0++] = past[i].slot;
for (int i = 0; i < fut_cnt && p0 < ANV_H264_MAX_REF_FRAMES; i++)
list0[p0++] = fut_slots[i];
for (int i = 0; i < lt_count && p0 < ANV_H264_MAX_REF_FRAMES; i++)
list0[p0++] = lt_slots[i];
list0[p0++] = fut[i].slot;
for (int i = 0; i < nlt && p0 < ANV_H264_MAX_REF_FRAMES; i++)
list0[p0++] = lt[i].slot;
for (int i = 0; i < fut_cnt && p1 < ANV_H264_MAX_REF_FRAMES; i++)
list1[p1++] = fut_slots[i];
list1[p1++] = fut[i].slot;
for (int i = 0; i < past_cnt && p1 < ANV_H264_MAX_REF_FRAMES; i++)
list1[p1++] = past_slots[i];
for (int i = 0; i < lt_count && p1 < ANV_H264_MAX_REF_FRAMES; i++)
list1[p1++] = lt_slots[i];
list1[p1++] = past[i].slot;
for (int i = 0; i < nlt && p1 < ANV_H264_MAX_REF_FRAMES; i++)
list1[p1++] = lt[i].slot;
anv_h264_swap_identical_l1(list0, NULL, list1, NULL, p1);
}
static void
@@ -415,6 +462,8 @@ anv_h264_apply_ref_pic_list_mod(
if (idc == 3) break;
if (idc > 3) { st->error = true; return; }
uint8_t found_slot = ANV_H264_INVALID_SLOT;
if (idc == 0 || idc == 1) {
unsigned diff = anv_h264_rbsp_ue(st) + 1;
if (st->error) return;
@@ -423,7 +472,6 @@ anv_h264_apply_ref_pic_list_mod(
else
picNumL = (picNumL + diff) % MaxFrameNum;
uint8_t found_slot = ANV_H264_INVALID_SLOT;
for (uint32_t j = 0; j < ref_slot_count; j++) {
const VkVideoDecodeH264DpbSlotInfoKHR *dpb =
vk_find_struct_const(ref_slots[j].pNext,
@@ -435,25 +483,29 @@ anv_h264_apply_ref_pic_list_mod(
break;
}
}
if (found_slot == ANV_H264_INVALID_SLOT) continue;
for (int k = active_count - 1; k > refIdxL; k--)
list[k] = list[k - 1];
list[refIdxL] = found_slot;
int w = refIdxL + 1;
for (int k = refIdxL + 1; k < active_count + 1 && w < ANV_H264_MAX_REF_FRAMES; k++) {
if (list[k] != found_slot)
list[w++] = list[k];
}
if (w < ANV_H264_MAX_REF_FRAMES)
list[w] = ANV_H264_INVALID_SLOT;
refIdxL++;
} else if (idc == 2) {
anv_h264_rbsp_ue(st);
} else {
uint32_t ltpn = anv_h264_rbsp_ue(st);
if (st->error) return;
for (uint32_t j = 0; j < ref_slot_count; j++) {
const VkVideoDecodeH264DpbSlotInfoKHR *dpb =
vk_find_struct_const(ref_slots[j].pNext,
VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR);
if (!dpb || !dpb->pStdReferenceInfo) continue;
if (dpb->pStdReferenceInfo->flags.used_for_long_term_reference &&
dpb->pStdReferenceInfo->FrameNum == ltpn) {
found_slot = (uint8_t)ref_slots[j].slotIndex;
break;
}
}
}
if (found_slot == ANV_H264_INVALID_SLOT) continue;
if (refIdxL >= active_count) continue;
anv_h264_ref_list_insert(list, NULL, active_count, refIdxL,
found_slot, 0);
refIdxL++;
} while (idc != 3);
}
@@ -531,29 +583,10 @@ anv_h264_apply_ref_pic_list_mod_field(
}
if (found_slot == ANV_H264_INVALID_SLOT) continue;
if (refIdx >= active_count) continue;
for (int k = active_count - 1; k > refIdx && k < ANV_H264_MAX_REF_FRAMES; k--) {
list[k] = list[k - 1];
listb[k] = listb[k - 1];
}
if (refIdx < ANV_H264_MAX_REF_FRAMES) {
list[refIdx] = found_slot;
listb[refIdx] = found_bottom;
}
int w = refIdx + 1;
for (int k = refIdx + 1;
k < active_count + 1 && k < ANV_H264_MAX_REF_FRAMES &&
w < ANV_H264_MAX_REF_FRAMES; k++) {
if (!(list[k] == found_slot && listb[k] == found_bottom)) {
list[w] = list[k];
listb[w] = listb[k];
w++;
}
}
if (w < ANV_H264_MAX_REF_FRAMES)
list[w] = ANV_H264_INVALID_SLOT;
anv_h264_ref_list_insert(list, listb, active_count, refIdx,
found_slot, found_bottom);
refIdx++;
} while (idc != 3);
}
@@ -711,9 +744,14 @@ anv_h264_parse_slice_header(
uint32_t cur_frame_num = pic_info->pStdPictureInfo->frame_num;
uint32_t MaxFrameNumForList = 1u << (sps->log2_max_frame_num_minus4 + 4);
int32_t curr_poc = cur_field_pic && cur_bottom ?
pic_info->pStdPictureInfo->PicOrderCnt[1] :
pic_info->pStdPictureInfo->PicOrderCnt[0];
int32_t poc_top = pic_info->pStdPictureInfo->PicOrderCnt[0];
int32_t poc_bot = pic_info->pStdPictureInfo->PicOrderCnt[1];
if (poc_top == INT32_MAX) poc_top = poc_bot;
if (poc_bot == INT32_MAX) poc_bot = poc_top;
/* 8.2.1 */
int32_t curr_poc = !cur_field_pic ? MIN2(poc_top, poc_bot) :
(cur_bottom ? poc_bot : poc_top);
if (cur_field_pic) {
anv_h264_build_field_ref_lists(slice_type, cur_sel, curr_poc,
@@ -723,6 +761,7 @@ anv_h264_parse_slice_header(
out->ref_list1, out->ref_list1_bottom);
} else {
anv_h264_build_default_ref_list(slice_type, curr_poc,
cur_frame_num, MaxFrameNumForList,
ref_slot_count, ref_slots,
out->ref_list0, out->ref_list1);
}
+450
View File
@@ -0,0 +1,450 @@
/*
* Copyright © 2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
* H.264 encode: MFC/MFX static state emission for the AVC encode pipeline.
*
* This lives in a separate translation unit because genX_pack.h and
* genX_video_pack.h share the same include guard (GFX7_IVB_PACK_H); a TU that
* includes both silently drops the second. The MFX and MFC encode commands
* need genX_video_pack.h, mirroring the decode split between genX_cmd_video.c
* and genX_cmd_buffer.c.
*
* Field names are taken from the decode paths in genX_cmd_video.c where the
* same commands are used. MFX_AVC_SLICE_STATE is the exception: it is not used
* by decode, so its fields are matched against the VA-API reference encoder
* (gen6_mfc_avc_slice_state, intel-vaapi-driver) rather than an in-tree user.
*
* All values below are validated only for the single-slice, I-frame, CQP case
* currently implemented. Inter prediction, references and rate control are not
* emitted.
*/
#include <string.h>
#include "anv_private.h"
#include "genxml/gen_macros.h"
#include "anv_genX.h"
#include "genxml/genX_video_pack.h"
#include "util/vl_zscan_data.h"
#include "anv_video_h264_bitstream.h"
void
genX(hasvk_mfc_emit_static_state)(struct anv_cmd_buffer *cmd_buffer,
const struct anv_image *source_image,
struct anv_address recon_address,
const StdVideoH264SequenceParameterSet *sps,
const StdVideoH264PictureParameterSet *pps,
struct anv_address dst_address,
uint32_t dst_page_offset,
uint64_t dst_buffer_range,
uint32_t width_in_mbs, uint32_t height_in_mbs,
bool is_p, struct anv_address ref_address)
{
struct anv_video_session *vid = cmd_buffer->video.vid;
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_MODE_SELECT), sel) {
sel.StandardSelect = SS_AVC;
sel.CodecSelect = Encode;
/* PAK requires the long-format interface and writes its output through
* the stream-out path. Deblocking is disabled here, so reconstruction
* uses the pre-deblocking destination. */
sel.DecoderShortFormatMode = LongFormatDriverInterface;
sel.StreamOutEnable = true;
sel.PreDeblockingOutputEnable = true;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_SURFACE_STATE), ss) {
ss.Width = source_image->vk.extent.width - 1;
ss.Height = height_in_mbs * 16 - 1;
ss.SurfaceFormat = PLANAR_420_8;
ss.InterleaveChroma = 1;
ss.SurfacePitch = source_image->planes[0].primary_surface.isl.row_pitch_B - 1;
ss.TiledSurface = source_image->planes[0].primary_surface.isl.tiling != ISL_TILING_LINEAR;
ss.TileWalk = TW_YMAJOR;
ss.YOffsetforUCb =
MIN2((source_image->planes[1].primary_surface.memory_range.offset -
source_image->planes[0].primary_surface.memory_range.offset) /
source_image->planes[0].primary_surface.isl.row_pitch_B, 32767u);
ss.YOffsetforVCr = 0;
}
struct anv_address mv_object_address =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_ENC_INPUT_MV].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_ENC_INPUT_MV].offset };
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_IND_OBJ_BASE_ADDR_STATE), index_obj) {
index_obj.MFCIndirectPAKBSEObjectAddress = dst_address;
/* Base for the per-MB indirect PAK-MV input data (inter/skip MBs). The
* MFC sets up its MV fetch unit from this base even when a given MB reads
* no MV data, so it must be a valid address rather than null. */
index_obj.MFXIndirectMVObjectAddress = mv_object_address;
#if GFX_VERx10 == 70
/* AccessUpperBound and CacheabilityControl exist under these names only
* on Gen7; Gen7.5 has only the MOCS field and Gen8 renames the bound.
* Encode is Gen7-only, so gate the extra fields accordingly. */
index_obj.MFCIndirectPAKBSEObjectAccessUpperBound =
anv_address_add(dst_address, dst_page_offset + dst_buffer_range);
index_obj.MFCIndirectPAKBSEObjectCacheabilityControl = 2;
index_obj.MFXIndirectMVObjectCacheabilityControl = 2;
#endif
}
/* Zero the first 32 bytes of the indirect MV buffer so every P macroblock,
* which reads its 8MV (32-byte) block from offset 0, sees a zero motion
* vector (co-located prediction). The MFC executes these serialising writes
* before it fetches the MV data for the PAK objects that follow. */
if (is_p) {
for (unsigned i = 0; i < 32; i += 8)
genX(emit_query_mi_write_u64)(cmd_buffer,
anv_address_add(mv_object_address, i), 0);
}
/* Scratch buffers are bound at video-session level via
* vkBindVideoSessionMemoryKHR (ANV_VID_MEM_H264_ENC_*). The reconstructed
* picture (pre-deblocking destination) is the caller's setup DPB slot.
*
* This block (PIPE_BUF_ADDR_STATE .. REF_IDX_STATE) is Gen7-only: field
* names and array layouts differ across gens (e.g. DirectMVBufferAddress[]
* vs the per-index fields on Gen7.5, and MFX_FQM_STATE not existing at all
* on Gen7.5/Gen8). */
#if GFX_VERx10 == 70
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_BUF_ADDR_STATE), buf) {
buf.PreDeblockingDestinationAddress = recon_address;
buf.OriginalUncompressedPictureSourceCacheabilityControl = 2;
buf.StreamOutDataDestinationCacheabilityControl = 2;
buf.IntraRowStoreScratchBufferCacheabilityControl = 2;
buf.DeblockingFilterRowStoreScratchBufferCacheabilityControl = 2;
buf.MBStatusBufferCacheabilityControl = 2;
memset(buf.ReferencePictureCacheabilityControl, 0,
sizeof(buf.ReferencePictureCacheabilityControl));
buf.OriginalUncompressedPictureSourceAddress =
anv_image_address(source_image,
&source_image->planes[0].primary_surface.memory_range);
buf.StreamOutDataDestinationAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_ENC_MB_STATUS].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_ENC_MB_STATUS].offset };
buf.IntraRowStoreScratchBufferAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_INTRA_ROW_STORE].offset };
buf.DeblockingFilterRowStoreScratchBufferAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE].offset };
buf.MBStatusBufferAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_ENC_MB_STATUS].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_ENC_MB_STATUS].offset };
/* PRM Vol2 Pt3, MFX_PIPE_BUF_ADDR_STATE, ReferencePictureAddress[0..15]:
* "AVC: Always specifies all 16 addresses ... All invalid addresses must
* be set to a valid address RefAddr[0] by the driver." Leaving these at
* zero risks a fault even when references are unused (I-frame), so fill
* them with the valid, mapped recon address. */
for (unsigned i = 0; i < ARRAY_SIZE(buf.ReferencePictureAddress); i++)
buf.ReferencePictureAddress[i] = recon_address;
/* Frame store 0 is the P-frame's reference (previous reconstructed
* frame); REF_IDX_STATE L0[0] maps ref index 0 to this frame store. */
if (is_p)
buf.ReferencePictureAddress[0] = ref_address;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_BSP_BUF_BASE_ADDR_STATE), bsp) {
/* Only the BSD/MPC row store is used by PAK; MPR row store and bitplane
* read buffer are left null, matching gen6_mfc_bsp_buf_base_addr_state. */
bsp.BSDMPCRowStoreScratchBufferAddress =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH].offset };
bsp.BSDMPCRowStoreScratchBufferCacheabilityControl = 2;
}
#endif /* GFX_VERx10 == 70 */
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_IMG_STATE), avc_img) {
avc_img.FrameWidth = MIN2(width_in_mbs - 1, 255u);
avc_img.FrameHeight = MIN2(height_in_mbs - 1, 254u);
avc_img.FrameSize = width_in_mbs * height_in_mbs - 1;
avc_img.ImageStructure = FramePicture;
avc_img.WeightedBiPredictionIDC = pps->weighted_bipred_idc;
avc_img.WeightedPredictionEnable = pps->flags.weighted_pred_flag;
avc_img.FirstChromaQPOffset = CLAMP(pps->chroma_qp_index_offset, -12, 12);
avc_img.SecondChromaQPOffset = CLAMP(pps->second_chroma_qp_index_offset, -12, 12);
avc_img.FieldPicture = false;
avc_img.MBAFFMode = false;
avc_img.FrameMBOnly = sps->flags.frame_mbs_only_flag;
avc_img._8x8IDCTTransformMode = pps->flags.transform_8x8_mode_flag;
avc_img.Direct8x8Inference = sps->flags.direct_8x8_inference_flag;
avc_img.ConstrainedIntraPrediction = pps->flags.constrained_intra_pred_flag;
avc_img.NonReferencePicture = false;
avc_img.EntropyCodingSyncEnable = pps->flags.entropy_coding_mode_flag;
avc_img.ChromaFormatIDC = sps->chroma_format_idc;
avc_img.MVUnpackedEnable = true;
avc_img.TrellisQuantizationChromaDisable = false;
avc_img.IntraMBConformanceMaxSize = 0xEE8;
avc_img.InterMBConformanceMaxSize = 0xBB8;
avc_img.NumberofReferenceFrames = is_p ? 1 : 0;
avc_img.NumberofActiveReferencePicturesfromL0 = is_p ? 1 : 0;
avc_img.NumberofActiveReferencePicturesfromL1 = 0;
avc_img.InitialQPValue = 0; /* per-slice QP comes from SLICE_STATE */
avc_img.PicOrderPresent = pps->flags.bottom_field_pic_order_in_frame_present_flag;
avc_img.DeltaPicOrderAlwaysZero = sps->flags.delta_pic_order_always_zero_flag;
avc_img.PicOrderCountType = sps->pic_order_cnt_type;
avc_img.DeblockingFilterControlPresent = pps->flags.deblocking_filter_control_present_flag;
avc_img.RedundantPicCountPresent = pps->flags.redundant_pic_cnt_present_flag;
avc_img.Log2MaxFrameNumber = MIN2((uint32_t)sps->log2_max_frame_num_minus4, 12u);
avc_img.Log2MaxPicOrderCountLSB = MIN2((uint32_t)sps->log2_max_pic_order_cnt_lsb_minus4, 12u);
avc_img.CurrentPictureFrameNumber = 0; /* single IDR frame */
}
/* Quantizer matrices. With no custom scaling list in the PPS,
* vk_video_derive_h264_scaling_list() returns the flat default (all 16). */
StdVideoH264ScalingLists scaling_lists;
vk_video_derive_h264_scaling_list(sps, pps, &scaling_lists);
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_4x4_Intra_MATRIX;
for (unsigned m = 0; m < 3; m++)
for (unsigned q = 0; q < 16; q++)
qm.ForwardQuantizerMatrix[m * 16 + vl_zscan_normal_16[q]] =
scaling_lists.ScalingList4x4[m][q];
}
if (pps->flags.transform_8x8_mode_flag) {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_QM_STATE), qm) {
qm.DWordLength = 16;
qm.AVC = AVC_8x8_Intra_MATRIX;
for (unsigned q = 0; q < 64; q++)
qm.ForwardQuantizerMatrix[vl_zscan_normal[q]] =
scaling_lists.ScalingList8x8[0][q];
}
}
/* MFX_FQM_STATE (forward quantizer matrix) does not exist on Gen7.5/Gen8;
* the block below is Gen7-only. For a flat scaling list the VA-API encoder
* (gen7_mfc_avc_fqm_state) programs the constant 0x10001000; a custom PPS
* scaling list would require the proper reciprocal and is not handled. */
#if GFX_VERx10 == 70
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_FQM_STATE), fqm) {
fqm.DWordLength = 32;
fqm.AVC = AVC_4x4_Intra_MATRIX;
for (unsigned q = 0; q < 32; q++)
fqm.ForwardQuantizerMatrix[q] = 0x10001000;
}
if (pps->flags.transform_8x8_mode_flag) {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_FQM_STATE), fqm) {
fqm.DWordLength = 32;
fqm.AVC = AVC_8x8_Intra_MATRIX;
for (unsigned q = 0; q < 32; q++)
fqm.ForwardQuantizerMatrix[q] = 0x10001000;
}
}
/* Direct MV buffers. I-frames scan no reference direct MVs, so only the
* current-picture write targets (top/bottom) are set. The POC list is
* filled as gen6_mfc_avc_directmode_state does (POCList[i] = i/2). */
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_DIRECTMODE_STATE), dmv) {
memset(dmv.DirectMVBufferAddress, 0, sizeof(dmv.DirectMVBufferAddress));
dmv.DirectMVBufferWriteAddress[0] =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_ENC_DIRECT_MV_TOP].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_ENC_DIRECT_MV_TOP].offset };
dmv.DirectMVBufferWriteAddress[1] =
(struct anv_address) { vid->vid_mem[ANV_VID_MEM_H264_ENC_DIRECT_MV_BOTTOM].mem->bo,
vid->vid_mem[ANV_VID_MEM_H264_ENC_DIRECT_MV_BOTTOM].offset };
for (unsigned i = 0; i < 32; i++)
dmv.POCList[i] = i / 2;
}
/* Reference index lists. Entries are set to the "non-existing" marker 0x80
* (intel_mfc_avc_ref_idx_state). For a P frame, L0[0] points at frame store
* 0: entry = (is_long_term<<6)|((top^bottom^1)<<5)|(frame_store_id<<1)|... ;
* for a short-term progressive frame at store 0 this is 0x20
* (intel_get_ref_idx_state_1). L1 is unused (P has no backward references). */
for (unsigned list = 0; list < 2; list++) {
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_REF_IDX_STATE), ref_idx) {
ref_idx.ReferencePictureListSelect = list;
memset(ref_idx.ReferenceListEntry, 0x80, sizeof(ref_idx.ReferenceListEntry));
if (is_p && list == 0)
ref_idx.ReferenceListEntry[0] = 0x20;
}
}
#endif /* GFX_VERx10 == 70 */
}
void
genX(hasvk_mfc_emit_slice)(struct anv_cmd_buffer *cmd_buffer,
const StdVideoH264SequenceParameterSet *sps,
const StdVideoH264PictureParameterSet *pps,
const StdVideoEncodeH264PictureInfo *pic_info,
const StdVideoEncodeH264SliceHeader *slice_hdr,
uint32_t slice_start_mb, uint32_t slice_end_mb,
uint32_t width_in_mbs, uint32_t height_in_mbs,
uint32_t qp, bool is_last_slice,
uint32_t dst_page_offset)
{
/* A P slice references the previous reconstructed frame; an I slice does
* not. B slices are out of scope. */
bool is_p = (slice_hdr->slice_type == STD_VIDEO_H264_SLICE_TYPE_P);
/* MFX_AVC_SLICE_STATE is not used by decode; fields are matched against the
* VA-API reference encoder (gen6_mfc_avc_slice_state). The slice covers the
* macroblock range [slice_start_mb, slice_end_mb) in raster order. */
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_AVC_SLICE_STATE), slice) {
slice.SliceType = is_p ? PSlice : ISlice; /* P=0,B=1,I=2 */
slice.NumberofReferencePicturesinInterpredictionList0 = is_p ? 1 : 0;
slice.SliceQuantizationParameter = qp;
slice.CABACInitIDC = is_p ? slice_hdr->cabac_init_idc : 0;
slice.DisableDeblockingFilterIndicator = 1;
slice.SliceAlphaC0OffsetDiv2 = 0;
slice.SliceBetaOffsetDiv2 = 0;
slice.SliceStartMBNumber = slice_start_mb;
slice.SliceHorizontalPosition = slice_start_mb % width_in_mbs;
slice.SliceVerticalPosition = slice_start_mb / width_in_mbs;
slice.NextSliceHorizontalPosition = slice_end_mb % width_in_mbs;
slice.NextSliceVerticalPosition = slice_end_mb / width_in_mbs;
slice.LastSliceGroup = is_last_slice;
slice.HeaderInsertionPresent = true;
slice.SliceDataInsertionPresent = true;
slice.TailInsertionPresent = true;
slice.EmulationByteSliceInsertEnable = true;
slice.CABACZeroWordInsertionEnable = false;
/* Without these the inserted slice header/tail are not emitted into the
* bitstream (gen6_mfc_avc_slice_state). */
slice.ResetRateControlCounter = true;
slice.RateControlStableTolerance = 4;
/* All slices point at the frame's bitstream start; the MFC advances the
* write pointer internally between slices because LoadBitstreamPointerPer-
* Slice is left 0 in MFX_AVC_IMG_STATE (pointer loaded once per frame).
* The start is a byte offset from the 4KiB-aligned PAK-BSE object base in
* MFX_IND_OBJ_BASE_ADDR_STATE, so it carries the sub-page part of the
* destination buffer offset that the page-granular base cannot encode. */
slice.IndirectPAKBSEDataStartAddress = dst_page_offset;
}
/* Slice header RBSP. SkipEmulationByteCount = 5 covers the 4-byte start
* code plus the 1-byte NAL header. */
uint8_t slice_header_buf[64];
uint32_t slice_header_bits =
anv_h264_build_encode_slice_header(slice_header_buf, sizeof(slice_header_buf),
sps, pps, pic_info, slice_hdr);
if (slice_header_bits == 0)
return;
uint32_t slice_header_dws = DIV_ROUND_UP(slice_header_bits, 32);
/* PRM Vol2 Pt3, MFX_PAK_INSERT_OBJECT, DataBitsInLastDW: valid range is
* [1,32]. A naive bits % 32 yields 0 when bits is a multiple of 32, which
* is illegal; map that to 32. */
uint32_t slice_header_bits_in_last_dw = slice_header_bits & 0x1f;
if (slice_header_bits_in_last_dw == 0)
slice_header_bits_in_last_dw = 32;
uint32_t *header_dst =
anv_batch_emitn(&cmd_buffer->batch, 2 + slice_header_dws,
GENX(MFX_PAK_INSERT_OBJECT),
.EmulationByteBitsInsertEnable = true,
.SkipEmulationByteCount = 5,
.DataBitsInLastDW = slice_header_bits_in_last_dw,
.LastHeader = true,
.EndofSlice = false);
if (header_dst)
memcpy(header_dst + 2, slice_header_buf, slice_header_dws * 4);
/* One MFC_AVC_PAK_OBJECT per macroblock. Field layout per PRM Vol2 Pt3
* §2.3.1.1 "PAK Object Inline Data Description". An I slice codes every MB as
* I_16x16 DC; a P slice codes every MB as P_Skip (see below).
*
* InlineData[0] (DW3): I-frame path:
* bit 13 IntraMbFlag = 1.
* bits 12:8 MbType5Bits = 23: the raw AVC mb_type (PRM: "unified
* encoding ... according to AVC Spec", not mb_type-1). Per
* Table 7-11, I_16x16 mb_type = 1 + PredMode + 4*CBPChroma +
* 12*CBPLuma, so 23 = I_16x16_2_2_1 (PredMode = DC).
* bits 19:17 CbpDcY/U/V = 1: DC sub-blocks coded.
* InlineData[4] (DW7) bits 1:0: LumaIntraMode[0] = DC (only [1:0] valid for
* Intra16x16).
* InlineData[6] (DW9): IntraStruct = per-MB IntraPredAvailFlags plus
* ChromaIntraPredMode = DC in bits [1:0].
*
* P-frame path: every MB is P_Skip. Per PRM §2.3.1.1, DW3 bit13 IntraMbFlag=0
* (inter), bits12:8 MbType5Bits=1 (BP_L0_16x16 — the only P type convertible
* to skip, PRM MbType table), bit2 SkipMbFlag=1 (forces P_Skip: HW uses the
* predicted MV and forces CBP to 0), bits22:20 MvFormat=0 (no MV data). No
* residual and no indirect MV buffer are needed; the reconstructed MB equals
* the motion-compensated (predicted-MV) reference block. For static content
* relative to the reference this is exact. DW7-9 carry the inter sub-mb shape
* (0 = 16x16) and reference indices L0/L1 (0 for the single reference). */
for (uint32_t mb = slice_start_mb; mb < slice_end_mb; mb++) {
uint32_t x = mb % width_in_mbs;
uint32_t y = mb / width_in_mbs;
bool last_mb = (mb == slice_end_mb - 1);
anv_batch_emit(&cmd_buffer->batch, GENX(MFC_AVC_PAK_OBJECT), pak) {
pak.IndirectPAKMVDataLength = 0;
pak.IndirectPAKMVDataStartAddressOffset = 0;
pak.InlineData[1] = (y << 8) | x; /* Cbp4x4Y=0, MbY/XCnt */
pak.InlineData[3] = ((uint32_t)last_mb << 26) | qp;
if (is_p) {
/* P_Skip: SkipMbFlag forces the skip (predicted MV = 0 for the
* uniform all-skip case, CBP forced to 0), so the reconstructed MB
* equals the co-located reference block. Exact for content identical
* to the reference. An inter MB requires a valid MvFormat (100/110);
* MvFormat=0 hangs the MFC, so 8MV (100) reads a zeroed 32-byte block
* from the dedicated indirect MV buffer.
*
* NOTE: coded inter (SkipMbFlag=0, CBP set) for changed content was
* implemented and works at QP0 (bit-exact residual) but shows per-MB
* blocky artefacts at higher QP — an encoder/decoder inter MV-
* predictor (mvp) mismatch, analogous to the intra edge-DC corner.
* Left as future work (needs per-MB mvp/neighbour handling); skip is
* the validated path. */
pak.IndirectPAKMVDataLength = 32; /* 8MV * 4 bytes */
pak.InlineData[0] = (1u << 8) /* MbType5Bits = 1: BP_L0_16x16 */
| (4u << 20) /* MvFormat = 100 (8MV) */
| (1u << 2); /* SkipMbFlag: force P_Skip */
pak.InlineData[1] = (y << 8) | x; /* Cbp4x4Y = 0 for skip */
pak.InlineData[2] = 0; /* Cbp4x4V/U = 0 for skip */
pak.InlineData[4] = 0; /* inter sub-mb shape = 16x16 */
pak.InlineData[5] = 0; /* ref index L0 = 0 */
pak.InlineData[6] = 0; /* ref index L1 = 0 */
pak.InlineData[7] = 0;
} else {
pak.InlineData[0] = 0x000e0000 /* CbpDcY/U/V = 1 */
| (1u << 13) /* IntraMbFlag */
| (0x17u << 8); /* MbType5Bits = 23: I_16x16 DC */
pak.InlineData[1] = 0xFFFF0000 | (y << 8) | x;
pak.InlineData[2] = 0x000F000F;
pak.InlineData[4] = 2; /* LumaIntraMode[0] = DC */
pak.InlineData[5] = 0;
/* IntraPredAvailFlags must reflect real neighbor availability so PAK
* DC prediction matches the decoder; intra prediction does not cross
* slice boundaries, so a neighbour counts only when its MB address is
* >= slice_start_mb as well as inside the picture.
* bit7 F, bit6 A, bit5 E: left | bit4 B: top | bit3 C: top-right |
* bit2 D: top-left. Bits [1:0] hold ChromaIntraPredMode (DC = 0). */
uint32_t intra_avail = 0;
if (x > 0 && mb - 1 >= slice_start_mb)
intra_avail |= (1u << 7) | (1u << 6) | (1u << 5);
if (y > 0 && mb - width_in_mbs >= slice_start_mb)
intra_avail |= (1u << 4);
if (y > 0 && x < width_in_mbs - 1 && mb - width_in_mbs + 1 >= slice_start_mb)
intra_avail |= (1u << 3);
if (x > 0 && y > 0 && mb - width_in_mbs - 1 >= slice_start_mb)
intra_avail |= (1u << 2);
pak.InlineData[6] = intra_avail;
pak.InlineData[7] = 0;
}
}
}
/* Slice tail: two zero bytes, marking end of slice (gen6_mfc_avc). */
uint32_t tail_data[2] = { 0, 0 };
uint32_t *tail_dst =
anv_batch_emitn(&cmd_buffer->batch, 2 + 2, GENX(MFX_PAK_INSERT_OBJECT),
.EmulationByteBitsInsertEnable = false,
.SkipEmulationByteCount = 2,
.DataBitsInLastDW = 8,
.LastHeader = true,
.EndofSlice = true);
if (tail_dst)
memcpy(tail_dst + 2, tail_data, sizeof(tail_data));
}
+151 -24
View File
@@ -90,7 +90,8 @@ static bool
is_video_queue_cmd_buffer(const struct anv_cmd_buffer *cmd_buffer)
{
struct anv_queue_family *queue_family = cmd_buffer->queue_family;
return (queue_family->queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) != 0;
return (queue_family->queueFlags & (VK_QUEUE_VIDEO_DECODE_BIT_KHR |
VK_QUEUE_VIDEO_ENCODE_BIT_KHR)) != 0;
}
void
@@ -2196,6 +2197,8 @@ emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
case ANV_DESCRIPTOR_SET_SHADER_CONSTANTS: {
struct anv_state surface_state =
anv_cmd_buffer_alloc_surface_state(cmd_buffer);
if (surface_state.map == NULL)
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
struct anv_address constant_data = {
.bo = cmd_buffer->device->instruction_state_pool.block_pool.bo,
@@ -2224,6 +2227,8 @@ emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
struct anv_state surface_state =
anv_cmd_buffer_alloc_surface_state(cmd_buffer);
if (surface_state.map == NULL)
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
const enum isl_format format =
anv_isl_format_for_descriptor_type(cmd_buffer->device,
@@ -2382,6 +2387,9 @@ emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
surface_state =
anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64);
if (surface_state.map == NULL)
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
enum isl_format format =
anv_isl_format_for_descriptor_type(cmd_buffer->device,
desc->type);
@@ -3220,6 +3228,30 @@ cmd_buffer_emit_streamout(struct anv_cmd_buffer *cmd_buffer)
anv_batch_emit_merge(&cmd_buffer->batch, dwords, streamout_state_dw);
}
/* Which vertex bindings the VS actually reads.
*
* Without VK_EXT_vertex_input_dynamic_state this was computed once at
* pipeline-creation time; with it, the attribute list is only known at draw
* time so we have to derive it from the dynamic state.
*/
static uint32_t
get_vb_used(const struct anv_graphics_pipeline *pipeline,
const struct vk_dynamic_graphics_state *dyn)
{
if (!pipeline->dynamic_vertex_input)
return pipeline->vb_used;
const uint64_t inputs_read = get_vs_prog_data(pipeline)->inputs_read;
uint32_t vb_used = 0;
u_foreach_bit(a, dyn->vi->attributes_valid) {
if (inputs_read & BITFIELD64_BIT(VERT_ATTRIB_GENERIC0 + a))
vb_used |= BITFIELD_BIT(dyn->vi->attributes[a].binding);
}
return vb_used;
}
ALWAYS_INLINE static void
genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer)
{
@@ -3240,9 +3272,21 @@ genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer)
*/
genX(cmd_buffer_apply_pipe_flushes)(cmd_buffer);
uint32_t vb_emit = cmd_buffer->state.gfx.vb_dirty & pipeline->vb_used;
/* With dynamic vertex input the pipeline has no baked vb_used; recompute
* which bindings the VS actually reads from the dynamic attribute list.
*/
const uint32_t vb_used = get_vb_used(pipeline, dyn);
/* A vertex input change alters strides and instancing, so every buffer we
* are about to emit has to be re-emitted along with the new elements.
*/
if (pipeline->dynamic_vertex_input &&
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VI))
cmd_buffer->state.gfx.vb_dirty |= vb_used;
uint32_t vb_emit = cmd_buffer->state.gfx.vb_dirty & vb_used;
if (cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_PIPELINE)
vb_emit |= pipeline->vb_used;
vb_emit |= vb_used;
if (vb_emit) {
const uint32_t num_buffers = __builtin_popcount(vb_emit);
@@ -3261,9 +3305,22 @@ genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer)
UNUSED uint32_t size = cmd_buffer->state.vertex_bindings[vb].size;
#if GFX_VER <= 7
bool per_instance = pipeline->vb[vb].instanced;
uint32_t divisor = pipeline->vb[vb].instance_divisor *
pipeline->instance_multiplier;
/* On gfx7 instancing lives in VERTEX_BUFFER_STATE rather than in
* a separate 3DSTATE_VF_INSTANCING packet, so it has to track the
* dynamic vertex input too.
*/
bool per_instance;
uint32_t divisor;
if (pipeline->dynamic_vertex_input) {
per_instance = dyn->vi->bindings[vb].input_rate ==
VK_VERTEX_INPUT_RATE_INSTANCE;
divisor = dyn->vi->bindings[vb].divisor *
pipeline->instance_multiplier;
} else {
per_instance = pipeline->vb[vb].instanced;
divisor = pipeline->vb[vb].instance_divisor *
pipeline->instance_multiplier;
}
#endif
state = (struct GENX(VERTEX_BUFFER_STATE)) {
@@ -3313,6 +3370,16 @@ genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer)
cmd_buffer->state.gfx.vb_dirty &= ~vb_emit;
/* With VK_EXT_vertex_input_dynamic_state the pipeline batch carries no
* 3DSTATE_VERTEX_ELEMENTS, so emit it here whenever the vertex input or
* the pipeline (and hence the VS's inputs_read) changed.
*/
if (pipeline->dynamic_vertex_input &&
((cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_PIPELINE) ||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VI))) {
genX(emit_vertex_input)(pipeline, &cmd_buffer->batch, dyn->vi);
}
uint32_t descriptors_dirty = cmd_buffer->state.descriptors_dirty &
pipeline->active_stages;
if (!cmd_buffer->state.gfx.dirty && !descriptors_dirty &&
@@ -3632,7 +3699,8 @@ update_dirty_vbs_for_gfx8_vb_flush(struct anv_cmd_buffer *cmd_buffer,
struct anv_graphics_pipeline *pipeline = cmd_buffer->state.gfx.pipeline;
const struct elk_vs_prog_data *vs_prog_data = get_vs_prog_data(pipeline);
uint64_t vb_used = pipeline->vb_used;
uint64_t vb_used = get_vb_used(pipeline,
&cmd_buffer->vk.dynamic_graphics_state);
if (vs_prog_data->uses_firstvertex ||
vs_prog_data->uses_baseinstance)
vb_used |= 1ull << ANV_SVGS_VB_INDEX;
@@ -4846,6 +4914,26 @@ void genX(CmdDispatchIndirect)(
}
#endif
#if GFX_VERx10 < 75
if (cmd_buffer->state.conditional_render_enabled) {
/* predicate &= conditional render result, computed fresh from the
* buffer since IVB has no GPR to latch it into.
*/
struct anv_cmd_state *cmd_state = &cmd_buffer->state;
mi_store(&b, mi_reg64(MI_PREDICATE_SRC0),
mi_mem32(cmd_state->conditional_render_value_addr));
mi_store(&b, mi_reg64(MI_PREDICATE_SRC1), mi_imm(0));
anv_batch_emit(batch, GENX(MI_PREDICATE), mip) {
mip.LoadOperation = cmd_state->conditional_render_inverted ?
LOAD_LOAD : LOAD_LOADINV;
mip.CombineOperation = COMBINE_AND;
mip.CompareOperation = COMPARE_SRCS_EQUAL;
}
}
#endif
#else /* GFX_VER > 7 */
if (cmd_buffer->state.conditional_render_enabled)
genX(cmd_emit_conditional_render_predicate)(cmd_buffer);
@@ -4923,6 +5011,12 @@ genX(flush_pipeline_select_gpgpu)(struct anv_cmd_buffer *cmd_buffer)
genX(flush_pipeline_select)(cmd_buffer, GPGPU);
}
void
genX(flush_pipeline_select_media)(struct anv_cmd_buffer *cmd_buffer)
{
genX(flush_pipeline_select)(cmd_buffer, Media);
}
void
genX(cmd_buffer_emit_gfx7_depth_flush)(struct anv_cmd_buffer *cmd_buffer)
{
@@ -5833,6 +5927,32 @@ genX(cmd_emit_conditional_render_predicate)(struct anv_cmd_buffer *cmd_buffer)
mip.CombineOperation = COMBINE_SET;
mip.CompareOperation = COMPARE_SRCS_EQUAL;
}
#else
/* IVB has no GPR, so we can't latch a precomputed result the way
* Gfx7.5+ does with ANV_PREDICATE_RESULT_REG. Instead, re-read the
* conditional render buffer directly before every draw and compute
* the predicate straight into MI_PREDICATE_RESULT. This is spec
* legal: "it's perfectly fine to read a value from the buffer once
* [per draw]" (VK_EXT_conditional_rendering spec commentary).
*/
struct anv_cmd_state *cmd_state = &cmd_buffer->state;
if (!cmd_state->conditional_render_enabled)
return;
struct mi_builder b;
mi_builder_init(&b, cmd_buffer->device->info, &cmd_buffer->batch);
mi_store(&b, mi_reg64(MI_PREDICATE_SRC0),
mi_mem32(cmd_state->conditional_render_value_addr));
mi_store(&b, mi_reg64(MI_PREDICATE_SRC1), mi_imm(0));
anv_batch_emit(&cmd_buffer->batch, GENX(MI_PREDICATE), mip) {
mip.LoadOperation = cmd_state->conditional_render_inverted ?
LOAD_LOAD : LOAD_LOADINV;
mip.CombineOperation = COMBINE_SET;
mip.CompareOperation = COMPARE_SRCS_EQUAL;
}
#endif
}
@@ -5857,27 +5977,35 @@ void genX(CmdBeginConditionalRenderingEXT)(
struct mi_builder b;
mi_builder_init(&b, cmd_buffer->device->info, &cmd_buffer->batch);
/* Section 19.4 of the Vulkan 1.1.85 spec says:
*
* If the value of the predicate in buffer memory changes
* while conditional rendering is active, the rendering commands
* may be discarded in an implementation-dependent way.
* Some implementations may latch the value of the predicate
* upon beginning conditional rendering while others
* may read it before every rendering command.
*
* So it's perfectly fine to read a value from the buffer once.
*/
struct mi_value value = mi_mem32(value_address);
struct mi_value value = mi_mem32(value_address);
/* Precompute predicate result, it is necessary to support secondary
* command buffers since it is unknown if conditional rendering is
* inverted when populating them.
*/
mi_store(&b, mi_reg64(ANV_PREDICATE_RESULT_REG),
isInverted ? mi_uge(&b, mi_imm(0), value) :
mi_ult(&b, mi_imm(0), value));
}
#else
void genX(CmdBeginConditionalRenderingEXT)(
VkCommandBuffer commandBuffer,
const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_buffer, buffer, pConditionalRenderingBegin->buffer);
struct anv_cmd_state *cmd_state = &cmd_buffer->state;
cmd_state->conditional_render_enabled = true;
cmd_state->conditional_render_value_addr =
anv_address_add(buffer->address, pConditionalRenderingBegin->offset);
cmd_state->conditional_render_inverted =
pConditionalRenderingBegin->flags &
VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT;
genX(cmd_buffer_apply_pipe_flushes)(cmd_buffer);
/* No MI_PREDICATE emission here — no GPR to precompute into.
* cmd_emit_conditional_render_predicate() re-reads the buffer and
* computes the predicate fresh before every draw instead. */
}
#endif
void genX(CmdEndConditionalRenderingEXT)(
VkCommandBuffer commandBuffer)
@@ -5887,7 +6015,6 @@ void genX(CmdEndConditionalRenderingEXT)(
cmd_state->conditional_render_enabled = false;
}
#endif
/* Set of stage bits for which are pipelined, i.e. they get queued
* by the command streamer for later execution.
+298 -20
View File
@@ -34,6 +34,8 @@
#include "anv_video_h264_slice.h"
#include "anv_genX.h"
static uint32_t
anv_h264_find_slice_nal(const uint8_t *buf, uint32_t off, uint32_t limit)
{
@@ -120,6 +122,15 @@ genX(CmdBeginVideoCodingKHR) (VkCommandBuffer commandBuffer,
cmd_buffer->video.vid = vid;
cmd_buffer->video.params = params;
/* Command buffers are reused from the pool and the reset path does not
* touch this struct, so encode_feedback_query_addr may hold a stale address
* from a previous use. Clear it here; otherwise CmdEncodeVideoKHR would try
* to write to that stale address even when no feedback query is active. */
cmd_buffer->video.encode_feedback_query_addr = ANV_NULL_ADDRESS;
if (getenv("HASVK_ENC_LOG"))
mesa_logi("ENC CmdBeginVideoCodingKHR op=%u refSlots=%u",
vid->vk.op, pBeginInfo->referenceSlotCount);
}
void
@@ -127,7 +138,8 @@ genX(CmdControlVideoCodingKHR) (VkCommandBuffer commandBuffer,
const VkVideoCodingControlInfoKHR *
pCodingControlInfo)
{
if (getenv("HASVK_ENC_LOG"))
mesa_logi("ENC CmdControlVideoCodingKHR flags=0x%x", pCodingControlInfo->flags);
}
void genX(CmdEndVideoCodingKHR) (VkCommandBuffer commandBuffer,
@@ -379,9 +391,12 @@ anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
#endif
}
uint64_t bs_abs = src_buffer->address.offset + frame_info->srcBufferOffset;
struct anv_address bs_base =
{ .bo = src_buffer->address.bo, .offset = bs_abs & ~4095ull };
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_IND_OBJ_BASE_ADDR_STATE), index_obj) {
index_obj.MFXIndirectBitstreamObjectAddress = anv_address_add(src_buffer->address,
frame_info->srcBufferOffset & ~4095);
index_obj.MFXIndirectBitstreamObjectAddress = bs_base;
#if GFX_VERx10 == 70
index_obj.MFXIndirectBitstreamObjectCacheabilityControl = 2;
#elif GFX_VERx10 == 75
@@ -555,6 +570,9 @@ anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
}
}
const uint8_t *bs_cpu = bs_map ? bs_map + (uintptr_t)(bs_abs & ~4095ull) : NULL;
uint32_t bs_page_off = (uint32_t)(bs_abs & 4095);
uint32_t mb_width = sps->pic_width_in_mbs_minus1 + 1;
uint32_t pic_height_in_map_units = sps->pic_height_in_map_units_minus1 + 1;
uint32_t mb_height = sps->flags.frame_mbs_only_flag ?
@@ -577,22 +595,20 @@ anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
h264_pic_info->pSliceOffsets[s + 1] :
frame_info->srcBufferRange;
uint32_t bo_base = frame_info->srcBufferOffset & ~4095u;
uint32_t page_off = frame_info->srcBufferOffset & 4095u;
uint32_t bo_nalu = bs_map ?
anv_h264_find_slice_nal(bs_map + bo_base,
page_off + slice_off,
page_off + buf_end) :
page_off + slice_off + 3;
uint32_t nalu_size = (page_off + buf_end > bo_nalu) ?
(page_off + buf_end - bo_nalu) : 0;
uint32_t bo_nalu = bs_cpu ?
anv_h264_find_slice_nal(bs_cpu,
bs_page_off + slice_off,
bs_page_off + buf_end) :
bs_page_off + slice_off + 3;
uint32_t nalu_size = (bs_page_off + buf_end > bo_nalu) ?
(bs_page_off + buf_end - bo_nalu) : 0;
bool ok = false;
if (bs_map && nalu_size > 0 &&
bo_base + bo_nalu + nalu_size <= src_buffer->address.bo->size) {
if (bs_cpu && nalu_size > 0 &&
(bs_abs & ~4095ull) + bo_nalu + nalu_size <=
src_buffer->address.bo->size) {
ok = anv_h264_parse_slice_header(
bs_map + bo_base, bo_nalu, nalu_size,
bs_cpu, bo_nalu, nalu_size,
sps, pps, h264_pic_info,
frame_info->referenceSlotCount,
frame_info->pReferenceSlots,
@@ -615,7 +631,7 @@ anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
}
}
uint32_t buffer_offset = frame_info->srcBufferOffset & 4095;
uint32_t buffer_offset = bs_page_off;
#define HEADER_OFFSET 3
for (unsigned s = 0; s < h264_pic_info->sliceCount; s++) {
bool last_slice = s == (h264_pic_info->sliceCount - 1);
@@ -887,7 +903,7 @@ anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
ss.SliceID = s & (uint32_t)((1u << 4) - 1);
}
if (ANV_DEBUG(VIDEO_DEBUG) && field_pic && cur) {
if (ANV_DEBUG(VIDEO_DEBUG) && cur) {
char l0[128] = {0}, l1[128] = {0};
for (int e = 0; e < 8; e++) {
char t[16];
@@ -909,9 +925,9 @@ anv_h264_decode_video(struct anv_cmd_buffer *cmd_buffer,
}
}
uint32_t bsd_nal = bs_map ?
uint32_t bsd_nal = bs_cpu ?
anv_h264_find_slice_nal(
bs_map + (frame_info->srcBufferOffset & ~4095u),
bs_cpu,
buffer_offset + current_offset,
buffer_offset + this_end) :
buffer_offset + current_offset + HEADER_OFFSET;
@@ -968,3 +984,265 @@ genX(CmdDecodeVideoKHR) (VkCommandBuffer commandBuffer,
UNREACHABLE("Unsupported video codec operation!");
}
}
/* MMIO offset of the MFC bitstream byte counter for the frame. On a single
* VDBOX (Gen7/7.5) the base is 0, so the raw offset is used directly. Matches
* i965 (i965_defines.h) and mainline anv for GFX_VER < 11. */
#define MFC_BITSTREAM_BYTECOUNT_FRAME_REG 0x128A0
/* Encodes a single H.264 I/IDR frame (CQP, single slice) via the MFC PAK
* pipeline: resolves the source, SPS/PPS, destination buffer and
* reconstructed-picture slot, then emits the static state and per-MB PAK
* objects. Inter prediction and references are not implemented. */
static VkResult
anv_h264_encode_video(struct anv_cmd_buffer *cmd_buffer,
const VkVideoEncodeInfoKHR *encode_info)
{
/* Source YUV frame. */
const struct anv_image_view *iv =
anv_image_view_from_handle(encode_info->srcPictureResource.imageViewBinding);
const struct anv_image *img = iv->image;
/* Constant QP from pNext -> VkVideoEncodeH264PictureInfoKHR ->
* pNaluSliceEntries[0].constantQp. Single slice, so only the first entry is
* read. */
const struct VkVideoEncodeH264PictureInfoKHR *h264_pic_info =
vk_find_struct_const(encode_info->pNext,
VIDEO_ENCODE_H264_PICTURE_INFO_KHR);
if (!h264_pic_info || h264_pic_info->naluSliceEntryCount < 1)
return VK_ERROR_INITIALIZATION_FAILED;
/* Macroblock dimensions from the image extent. */
uint32_t width_in_mbs = DIV_ROUND_UP(img->vk.extent.width, 16);
uint32_t height_in_mbs = DIV_ROUND_UP(img->vk.extent.height, 16);
uint32_t total_mbs = width_in_mbs * height_in_mbs;
/* SPS/PPS. The PPS id lives in StdVideoEncodeH264PictureInfo, not in the
* slice header. */
if (!h264_pic_info->pStdPictureInfo)
return VK_ERROR_INITIALIZATION_FAILED;
uint32_t pps_id = h264_pic_info->pStdPictureInfo->pic_parameter_set_id;
const StdVideoH264PictureParameterSet *pps =
vk_video_find_h264_enc_std_pps(&cmd_buffer->video.params->vk, pps_id);
if (!pps)
return VK_ERROR_INITIALIZATION_FAILED;
const StdVideoH264SequenceParameterSet *sps =
vk_video_find_h264_enc_std_sps(&cmd_buffer->video.params->vk,
pps->seq_parameter_set_id);
if (!sps)
return VK_ERROR_INITIALIZATION_FAILED;
/* DEBUG (HASVK_ENC_LOG): dump the client-supplied encode parameters so a
* general client (ffmpeg h264_vulkan) can be compared to the test harness. */
if (getenv("HASVK_ENC_LOG")) {
const struct isl_surf *s0 = &img->planes[0].primary_surface.isl;
const VkVideoInlineQueryInfoKHR *inline_q =
vk_find_struct_const(encode_info->pNext, VIDEO_INLINE_QUERY_INFO_KHR);
const StdVideoEncodeH264SliceHeader *sh0 =
h264_pic_info->pNaluSliceEntries[0].pStdSliceHeader;
mesa_logi("ENC src img %ux%u planes=%u fmt=%u tiling=%u pitch=%u aspects=0x%x",
img->vk.extent.width, img->vk.extent.height, img->n_planes,
s0->format, s0->tiling, s0->row_pitch_B, img->vk.aspects);
if (encode_info->pSetupReferenceSlot &&
encode_info->pSetupReferenceSlot->pPictureResource) {
const struct anv_image_view *riv = anv_image_view_from_handle(
encode_info->pSetupReferenceSlot->pPictureResource->imageViewBinding);
const struct isl_surf *rs = &riv->image->planes[0].primary_surface.isl;
mesa_logi("ENC recon img %ux%u planes=%u fmt=%u tiling=%u pitch=%u aspects=0x%x",
riv->image->vk.extent.width, riv->image->vk.extent.height,
riv->image->n_planes, rs->format, rs->tiling, rs->row_pitch_B,
riv->image->vk.aspects);
}
mesa_logi("ENC SPS profile=%u chroma=%u frame_mbs_only=%u wxh_mbs=%ux%u "
"poc_type=%u",
sps->profile_idc, sps->chroma_format_idc,
sps->flags.frame_mbs_only_flag,
sps->pic_width_in_mbs_minus1 + 1,
sps->pic_height_in_map_units_minus1 + 1, sps->pic_order_cnt_type);
mesa_logi("ENC PPS entropy=%u transform8x8=%u deblock_ctrl=%u "
"num_ref_l0=%u init_qp=%d",
pps->flags.entropy_coding_mode_flag,
pps->flags.transform_8x8_mode_flag,
pps->flags.deblocking_filter_control_present_flag,
pps->num_ref_idx_l0_default_active_minus1 + 1,
pps->pic_init_qp_minus26 + 26);
mesa_logi("ENC scaling: sps_present=%u pps_present=%u sps_pScaling=%p "
"pps_pScaling=%p level=%u log2maxfn=%u cip=%u",
sps->flags.seq_scaling_matrix_present_flag,
pps->flags.pic_scaling_matrix_present_flag,
(void *)sps->pScalingLists, (void *)pps->pScalingLists,
sps->level_idc, sps->log2_max_frame_num_minus4,
pps->flags.constrained_intra_pred_flag);
mesa_logi("ENC slices=%u slice0_type=%u qp=%d refSlots=%u setup=%p "
"inline_query=%p dstOff=%llu dstRange=%llu",
h264_pic_info->naluSliceEntryCount,
sh0 ? sh0->slice_type : 99u,
h264_pic_info->pNaluSliceEntries[0].constantQp,
encode_info->referenceSlotCount,
(void *)encode_info->pSetupReferenceSlot, (void *)inline_q,
(unsigned long long)encode_info->dstBufferOffset,
(unsigned long long)encode_info->dstBufferRange);
}
/* Destination bitstream buffer. MFX_IND_OBJ_BASE_ADDR_STATE holds the
* PAK-BSE object address in bits 31:12 only, so the base handed to the
* hardware must be 4KiB aligned or the low bits are silently dropped and
* the PAK writes land at the wrong address. Align the base down and fold
* the remainder into MFX_AVC_SLICE_STATE's IndirectPAKBSEDataStartAddress,
* a 29-bit byte offset from that base. This mirrors the decode-side
* bitstream base handling. */
ANV_FROM_HANDLE(anv_buffer, dst_buffer, encode_info->dstBuffer);
uint64_t bs_abs = dst_buffer->address.offset + encode_info->dstBufferOffset;
struct anv_address dst_address =
{ .bo = dst_buffer->address.bo, .offset = bs_abs & ~4095ull };
uint32_t dst_page_off = (uint32_t)(bs_abs & 4095);
/* Reconstructed picture (pre-deblocking destination). PAK requires a valid
* target since PreDeblockingOutputEnable is set, so the setup DPB slot is
* mandatory; there is no internal recon-image fallback. */
if (!encode_info->pSetupReferenceSlot ||
!encode_info->pSetupReferenceSlot->pPictureResource)
return VK_ERROR_INITIALIZATION_FAILED;
const struct anv_image_view *recon_iv =
anv_image_view_from_handle(
encode_info->pSetupReferenceSlot->pPictureResource->imageViewBinding);
struct anv_address recon_address =
anv_image_dpb_address(recon_iv,
encode_info->pSetupReferenceSlot->pPictureResource->baseArrayLayer);
/* P frame: the reconstructed picture of the previous frame, supplied as
* pReferenceSlots[0], is the single L0 reference. Absence of a reference
* slot means this is an I frame. */
bool is_p = encode_info->referenceSlotCount > 0 &&
encode_info->pReferenceSlots &&
encode_info->pReferenceSlots[0].pPictureResource;
struct anv_address ref_address = ANV_NULL_ADDRESS;
if (is_p) {
const struct anv_image_view *ref_iv =
anv_image_view_from_handle(
encode_info->pReferenceSlots[0].pPictureResource->imageViewBinding);
ref_address =
anv_image_dpb_address(ref_iv,
encode_info->pReferenceSlots[0].pPictureResource->baseArrayLayer);
}
/* Frame-level static state, emitted once before any slice. */
genX(hasvk_mfc_emit_static_state)(cmd_buffer, img, recon_address, sps, pps,
dst_address, dst_page_off,
encode_info->dstBufferRange,
width_in_mbs, height_in_mbs, is_p, ref_address);
/* Emit each slice. Slice s covers the macroblock range
* [first_mb_in_slice[s], first_mb_in_slice[s+1]); the last slice runs to the
* end of the frame. Each NALU slice entry carries its own QP and slice
* header. The MFC appends slices in the destination buffer automatically. */
uint32_t slice_count = h264_pic_info->naluSliceEntryCount;
for (uint32_t s = 0; s < slice_count; s++) {
const VkVideoEncodeH264NaluSliceInfoKHR *entry =
&h264_pic_info->pNaluSliceEntries[s];
const StdVideoEncodeH264SliceHeader *sh = entry->pStdSliceHeader;
if (!sh)
return VK_ERROR_INITIALIZATION_FAILED;
if (entry->constantQp < 0 || entry->constantQp > 51)
return VK_ERROR_INITIALIZATION_FAILED;
uint32_t slice_start_mb = sh->first_mb_in_slice;
uint32_t slice_end_mb = total_mbs;
if (s + 1 < slice_count) {
const StdVideoEncodeH264SliceHeader *next_sh =
h264_pic_info->pNaluSliceEntries[s + 1].pStdSliceHeader;
if (!next_sh)
return VK_ERROR_INITIALIZATION_FAILED;
slice_end_mb = next_sh->first_mb_in_slice;
}
/* H.264 requires the first slice of a picture to start at macroblock 0
* (7.4.3: first_mb_in_slice of the first slice is 0). ffmpeg's h264_vulkan
* encoder violates this — it passes first_mb_in_slice=1 for the sole slice.
* Trusting that value skips MB 0, so the MFC only receives total_mbs-1 PAK
* objects for a frame it knows has total_mbs macroblocks; it then waits
* forever for the missing MB and the VCS ring hangs ("stopped heartbeat",
* no page fault, parked on MFC_AVC_PAK_OBJECT). Force the first slice to
* start at MB 0 so the frame is fully covered and the emitted slice header
* stays consistent with the coded data. */
if (s == 0)
slice_start_mb = 0;
if (getenv("HASVK_ENC_LOG"))
mesa_logi("ENC slice[%u] first_mb_in_slice=%u -> start=%u end=%u total_mbs=%u",
s, sh->first_mb_in_slice, slice_start_mb, slice_end_mb, total_mbs);
if (slice_start_mb >= slice_end_mb || slice_end_mb > total_mbs)
return VK_ERROR_INITIALIZATION_FAILED;
/* Corrected slice header: the bitstream writer emits first_mb_in_slice
* directly from the std struct, so hand it the normalised start MB to keep
* the written header in sync with SLICE_STATE and the PAK object range. */
StdVideoEncodeH264SliceHeader sh_fixed = *sh;
sh_fixed.first_mb_in_slice = slice_start_mb;
genX(hasvk_mfc_emit_slice)(cmd_buffer, sps, pps,
h264_pic_info->pStdPictureInfo, &sh_fixed,
slice_start_mb, slice_end_mb,
width_in_mbs, height_in_mbs,
(uint32_t)entry->constantQp,
s + 1 == slice_count, dst_page_off);
}
/* Write the VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR result here, where the
* real dstBufferOffset/Range is known. slot[0] = availability, slot[8] =
* bitstream buffer offset, slot[16] = bytes written. The byte count is read
* from the MFC bitstream byte counter (MFC_BITSTREAM_BYTECOUNT_FRAME_REG),
* which holds the number of bytes the PAK unit emitted for the frame. The
* counter is only stable after the MFC pipe has drained, so a CS stall plus
* MFX_WAIT is issued first (mirroring the frame-end sync in
* CmdEndVideoCodingKHR). */
if (cmd_buffer->video.encode_feedback_query_addr.bo != NULL) {
struct anv_address addr = cmd_buffer->video.encode_feedback_query_addr;
#if GFX_VER == 8
anv_batch_emit(&cmd_buffer->batch, GENX(MI_FLUSH_DW), flush) {
flush.PostSyncOperation = 0;
}
#elif GFX_VER <= 75
anv_batch_emit(&cmd_buffer->batch, GENX(PIPE_CONTROL), pc) {
pc.CommandStreamerStallEnable = 1;
pc.StallAtPixelScoreboard = 1;
}
anv_batch_emit(&cmd_buffer->batch, GENX(MFX_WAIT), wait) {
wait.MFXSyncControlFlag = 1;
}
#endif
genX(emit_query_mi_write_u64)(cmd_buffer, addr, 1);
genX(emit_query_mi_write_u64)(cmd_buffer, anv_address_add(addr, 8), 0);
genX(emit_query_mi_write_reg32)(cmd_buffer, anv_address_add(addr, 16),
MFC_BITSTREAM_BYTECOUNT_FRAME_REG);
}
return VK_SUCCESS;
}
void
genX(CmdEncodeVideoKHR) (VkCommandBuffer commandBuffer,
const VkVideoEncodeInfoKHR * pEncodeInfo)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
if (!cmd_buffer->video.vid)
abort();
switch (cmd_buffer->video.vid->vk.op) {
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR: {
/* vkCmdEncodeVideoKHR returns void, so on failure the command buffer is
* marked errored and the error is surfaced at vkEndCommandBuffer /
* vkQueueSubmit. */
VkResult result = anv_h264_encode_video(cmd_buffer, pEncodeInfo);
if (result != VK_SUCCESS)
anv_batch_set_error(&cmd_buffer->batch, result);
break;
}
default:
UNREACHABLE("Unsupported video codec operation!");
}
}
+20 -11
View File
@@ -89,9 +89,16 @@ vertex_element_comp_control(enum isl_format format, unsigned comp)
}
}
static void
emit_vertex_input(struct anv_graphics_pipeline *pipeline,
const struct vk_vertex_input_state *vi)
/* Emits 3DSTATE_VERTEX_ELEMENTS (plus VF_INSTANCING/VF_SGVS on Gfx8+) for the
* given vertex input state. With VK_EXT_vertex_input_dynamic_state this is
* called from the command buffer at draw time; otherwise it is baked into the
* pipeline batch at pipeline-creation time. Everything it needs beyond the
* pipeline itself comes from `vi`, so both callers share this one path.
*/
void
genX(emit_vertex_input)(struct anv_graphics_pipeline *pipeline,
struct anv_batch *batch,
const struct vk_vertex_input_state *vi)
{
const struct elk_vs_prog_data *vs_prog_data = get_vs_prog_data(pipeline);
@@ -116,7 +123,7 @@ emit_vertex_input(struct anv_graphics_pipeline *pipeline,
uint32_t *p;
const uint32_t num_dwords = 1 + total_elems * 2;
p = anv_batch_emitn(&pipeline->base.batch, num_dwords,
p = anv_batch_emitn(batch, num_dwords,
GENX(3DSTATE_VERTEX_ELEMENTS));
if (!p)
return;
@@ -185,9 +192,10 @@ emit_vertex_input(struct anv_graphics_pipeline *pipeline,
* that controls instancing. On Haswell and prior, that's part of
* VERTEX_BUFFER_STATE which we emit later.
*/
anv_batch_emit(&pipeline->base.batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
bool per_instance = pipeline->vb[binding].instanced;
uint32_t divisor = pipeline->vb[binding].instance_divisor *
anv_batch_emit(batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
bool per_instance = vi->bindings[binding].input_rate ==
VK_VERTEX_INPUT_RATE_INSTANCE;
uint32_t divisor = vi->bindings[binding].divisor *
pipeline->instance_multiplier;
vfi.InstancingEnable = per_instance;
@@ -229,14 +237,14 @@ emit_vertex_input(struct anv_graphics_pipeline *pipeline,
GENX(VERTEX_ELEMENT_STATE_pack)(NULL, &p[1 + id_slot * 2], &element);
#if GFX_VER >= 8
anv_batch_emit(&pipeline->base.batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
anv_batch_emit(batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
vfi.VertexElementIndex = id_slot;
}
#endif
}
#if GFX_VER >= 8
anv_batch_emit(&pipeline->base.batch, GENX(3DSTATE_VF_SGVS), sgvs) {
anv_batch_emit(batch, GENX(3DSTATE_VF_SGVS), sgvs) {
sgvs.VertexIDEnable = vs_prog_data->uses_vertexid;
sgvs.VertexIDComponentNumber = 2;
sgvs.VertexIDElementOffset = id_slot;
@@ -262,7 +270,7 @@ emit_vertex_input(struct anv_graphics_pipeline *pipeline,
&element);
#if GFX_VER >= 8
anv_batch_emit(&pipeline->base.batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
anv_batch_emit(batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
vfi.VertexElementIndex = drawid_slot;
}
#endif
@@ -1886,7 +1894,8 @@ genX(graphics_pipeline_emit)(struct anv_graphics_pipeline *pipeline,
gfx7_emit_vs_workaround_flush(elk);
#endif
emit_vertex_input(pipeline, state->vi);
if (!BITSET_TEST(state->dynamic, MESA_VK_DYNAMIC_VI))
genX(emit_vertex_input)(pipeline, &pipeline->base.batch, state->vi);
/* DIAGNOSTIC v2: always emit here (both Gen7 and Gen8+), matching
* vanilla hasvk's original position exactly. */
+85 -1
View File
@@ -71,6 +71,35 @@ genX(emit_query_mi_flush_availability)(struct anv_cmd_buffer *cmd_buffer,
}
}
/* Writes an arbitrary 64-bit value to a query slot, unlike
* emit_query_mi_flush_availability() which only writes a boolean. Used for the
* buffer-offset and bytes-written values of a video encode feedback query. */
void
genX(emit_query_mi_write_u64)(struct anv_cmd_buffer *cmd_buffer,
struct anv_address addr,
uint64_t value)
{
anv_batch_emit(&cmd_buffer->batch, GENX(MI_FLUSH_DW), flush) {
flush.PostSyncOperation = WriteImmediateData;
flush.Address = addr;
flush.ImmediateData = value;
}
}
/* Copies a 32-bit MMIO register into a query slot, zero-extended to 64 bits.
* Used to read the MFC bitstream byte counter (MFC_BITSTREAM_BYTECOUNT_FRAME)
* into the bytes-written field of a video encode feedback query. The caller
* must have drained the MFC pipe first so the counter holds the final value. */
void
genX(emit_query_mi_write_reg32)(struct anv_cmd_buffer *cmd_buffer,
struct anv_address addr,
uint32_t reg)
{
struct mi_builder b;
mi_builder_init(&b, cmd_buffer->device->info, &cmd_buffer->batch);
mi_store(&b, mi_mem64(addr), mi_reg32(reg));
}
VkResult genX(CreateQueryPool)(
VkDevice _device,
const VkQueryPoolCreateInfo* pCreateInfo,
@@ -178,6 +207,10 @@ VkResult genX(CreateQueryPool)(
case VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR:
uint64s_per_slot = 1;
break;
case VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR:
/* availability + buffer-offset + bytes-written. */
uint64s_per_slot = 1 + 2;
break;
default:
UNREACHABLE("Invalid query type");
}
@@ -469,7 +502,8 @@ VkResult genX(GetQueryPoolResults)(
pool->type == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR ||
pool->type == VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL ||
pool->type == VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT ||
pool->type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR);
pool->type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR ||
pool->type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR);
if (vk_device_is_lost(&device->vk))
return VK_ERROR_DEVICE_LOST;
@@ -615,6 +649,23 @@ VkResult genX(GetQueryPoolResults)(
cpu_write_query_result(pData, flags, idx, result);
break;
case VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR: {
/* slot[0] = availability, slot[1] = buffer offset (always 0 for a
* single slice), slot[2] = bytes written (the MFC bitstream byte
* count read from MFC_BITSTREAM_BYTECOUNT_FRAME_REG; see
* anv_h264_encode_video()). */
uint64_t *slot = query_slot(pool, firstQuery + i);
if (write_results) {
cpu_write_query_result(pData, flags, idx, slot[1]);
cpu_write_query_result(pData, flags, idx + 1, slot[2]);
}
/* Two feedback values (offset, bytes written); advance past both so an
* appended availability/status word lands after them rather than
* overwriting the byte count. */
idx += 2;
break;
}
default:
UNREACHABLE("invalid pool type");
}
@@ -625,6 +676,17 @@ VkResult genX(GetQueryPoolResults)(
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
cpu_write_query_result(pData, flags, idx, available);
/* VK_KHR_video_queue: when the app requests the per-query status (as
* ffmpeg's h264_vulkan does for encode-feedback queries), append a
* VkQueryResultStatusKHR. A completed query reports COMPLETE (1); an
* unavailable one reports NOT_READY (0). Without this the app reads a
* stale/zero status and treats the encode as failed ("Unable to
* encode: 0") even though the bitstream was produced. */
if (flags & VK_QUERY_RESULT_WITH_STATUS_BIT_KHR)
cpu_write_query_result(pData, flags, idx,
available ? VK_QUERY_RESULT_STATUS_COMPLETE_KHR
: VK_QUERY_RESULT_STATUS_NOT_READY_KHR);
pData += stride;
if (pData >= data_end)
break;
@@ -818,6 +880,13 @@ void genX(CmdResetQueryPool)(
genX(emit_query_mi_flush_availability)(cmd_buffer, anv_query_address(pool, firstQuery + i), false);
break;
case VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR:
/* Without this case the query type would fall through to the UNREACHABLE
* default, which under -DNDEBUG is undefined behavior on reset. */
for (uint32_t i = 0; i < queryCount; i++)
genX(emit_query_mi_flush_availability)(cmd_buffer, anv_query_address(pool, firstQuery + i), false);
break;
default:
UNREACHABLE("Unsupported query type");
}
@@ -1119,6 +1188,14 @@ void genX(CmdBeginQueryIndexedEXT)(
case VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR:
genX(emit_query_mi_flush_availability)(cmd_buffer, query_addr, false);
break;
case VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR:
/* The offset/bytes-written values are written by the enclosed
* vkCmdEncodeVideoKHR (only it knows the real dstBufferOffset/Range; see
* anv_h264_encode_video()). Here we just mark the query not-ready and
* record the address for the encode command to write to. */
genX(emit_query_mi_flush_availability)(cmd_buffer, query_addr, false);
cmd_buffer->video.encode_feedback_query_addr = query_addr;
break;
default:
UNREACHABLE("");
}
@@ -1290,6 +1367,13 @@ void genX(CmdEndQueryIndexedEXT)(
genX(emit_query_mi_flush_availability)(cmd_buffer, query_addr, true);
break;
case VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR:
/* The data and availability were already written by
* anv_h264_encode_video() earlier in the same batch; just clear the
* active-query tracking here. */
cmd_buffer->video.encode_feedback_query_addr = ANV_NULL_ADDRESS;
break;
default:
UNREACHABLE("");
}
+1 -1
View File
@@ -408,7 +408,7 @@ VkResult genX(CreateSampler)(
pCreateInfo->borderColor *
border_color_stride;
} else {
assert(GFX_VER >= 8);
assert(GFX_VER >= 7);
sampler->custom_border_color =
anv_state_reserved_pool_alloc(&device->custom_border_colors);
border_color_offset = sampler->custom_border_color.offset;
+3
View File
@@ -63,6 +63,7 @@ anv_per_hw_ver_files = files(
'genX_pipeline.c',
'genX_query.c',
'genX_state.c',
'anv_video_mfc.c',
)
foreach g : [['70', ['gfx7_cmd_buffer.c']],
['75', ['gfx7_cmd_buffer.c']],
@@ -100,6 +101,7 @@ libanv_files = files(
'anv_formats.c',
'anv_genX.h',
'anv_image.c',
'anv_host_image_copy.c',
'anv_measure.c',
'anv_measure.h',
'anv_nir.h',
@@ -116,6 +118,7 @@ libanv_files = files(
'anv_util.c',
'anv_utrace.c',
'anv_video.c',
'anv_video_h264_bitstream.c',
'anv_video_h264_slice.c',
'anv_wsi.c',
)
@@ -0,0 +1,53 @@
{ 0x00800001, 0x24000061, 0x00000000, 0x00000000 },
{ 0x00800001, 0x24400061, 0x00000000, 0x00000000 },
{ 0x00800001, 0x24800061, 0x00000000, 0x00000000 },
{ 0x00800001, 0x24c00061, 0x00000000, 0x00000000 },
{ 0x00200009, 0x24002e25, 0x004500a0, 0x00040004 },
{ 0x00000040, 0x24003ca5, 0x00000400, 0xfff8fff8 },
{ 0x00000040, 0x24043ca5, 0x00000404, 0xffffffff },
{ 0x00000001, 0x240800e1, 0x00000000, 0x0000001f },
{ 0x00000001, 0x24140231, 0x00000014, 0x00000000 },
{ 0x00200009, 0x24202e25, 0x004500a0, 0x00040004 },
{ 0x00000040, 0x24203ca5, 0x00000420, 0xfffcfffc },
{ 0x00000001, 0x242800e1, 0x00000000, 0x000f0003 },
{ 0x00000001, 0x24340231, 0x00000014, 0x00000000 },
{ 0x00200009, 0x24482e29, 0x004500a0, 0x00040004 },
{ 0x00000001, 0x24540231, 0x00000014, 0x00000000 },
{ 0x00000041, 0x24884521, 0x000000a2, 0x000000a1 },
{ 0x00000040, 0x24884421, 0x00000488, 0x000000a0 },
{ 0x00000001, 0x24940231, 0x00000014, 0x00000000 },
{ 0x00600001, 0x28000021, 0x008d0400, 0x00000000 },
{ 0x04600031, 0x23801cb1, 0x00000800, 0x02190004 },
{ 0x00600001, 0x28000021, 0x008d0420, 0x00000000 },
{ 0x04600031, 0x23a01cb1, 0x00000800, 0x02290004 },
{ 0x00600001, 0x28000021, 0x008d0440, 0x00000000 },
{ 0x00600001, 0x28400061, 0x00000000, 0x00000000 },
{ 0x00600001, 0x28000021, 0x008d0440, 0x00000000 },
{ 0x00600001, 0x24600061, 0x00000000, 0x00000000 },
{ 0x01000005, 0x20002e28, 0x000000a4, 0x00010001 },
{ 0x00010001, 0x247c0171, 0x00000000, 0x00020002 },
{ 0x00000001, 0x247d0231, 0x000000a5, 0x00000000 },
{ 0x00600001, 0x28200021, 0x008d0460, 0x00000000 },
{ 0x00600001, 0x28400061, 0x00000000, 0x00000000 },
{ 0x00000001, 0x23800061, 0x00000000, 0x00000000 },
{ 0x00000005, 0x23840c21, 0x00000384, 0xff000000 },
{ 0x00600001, 0x28600021, 0x008d0380, 0x00000000 },
{ 0x00600001, 0x288000e1, 0x00000000, 0x00000000 },
{ 0x00800001, 0x28800231, 0x00cf03a3, 0x00000000 },
{ 0x00000001, 0x28900061, 0x00000000, 0x11111111 },
{ 0x00000001, 0x24000221, 0x000000a8, 0x00000000 },
{ 0x00000005, 0x24200c21, 0x00000400, 0x00000006 },
{ 0x00000009, 0x24040c21, 0x00000420, 0x0000000a },
{ 0x00000005, 0x24200c21, 0x00000400, 0x00000038 },
{ 0x00000009, 0x24240c21, 0x00000420, 0x00000005 },
{ 0x00000040, 0x24000421, 0x00000404, 0x00000424 },
{ 0x00000040, 0x22000c20, 0x00000400, 0x0a184000 },
{ 0x08000031, 0x21800221, 0x00000800, 0x00000200 },
{ 0x00600001, 0x28000021, 0x008d0480, 0x00000000 },
{ 0x00000001, 0x28200021, 0x00000180, 0x00000000 },
{ 0x00000001, 0x28240021, 0x00000190, 0x00000000 },
{ 0x00000001, 0x28280021, 0x00000194, 0x00000000 },
{ 0x00000001, 0x282c0021, 0x00000198, 0x00000000 },
{ 0x0a800031, 0x20001cac, 0x00000800, 0x040a0003 },
{ 0x00600001, 0x2e000021, 0x008d0000, 0x00000000 },
{ 0x07800031, 0x24001ca8, 0x00000e00, 0x82000010 },