vulkan/anv_nir.h \
vulkan/anv_nir_add_base_work_group_id.c \
vulkan/anv_nir_apply_pipeline_layout.c \
+ vulkan/anv_nir_compute_push_layout.c \
vulkan/anv_nir_lower_multiview.c \
vulkan/anv_nir_lower_push_constants.c \
vulkan/anv_nir_lower_ycbcr_textures.c \
struct brw_stage_prog_data *prog_data,
struct anv_pipeline_bind_map *map);
+void anv_compute_push_layout(const struct anv_physical_device *pdevice,
+ struct brw_stage_prog_data *prog_data,
+ struct anv_pipeline_bind_map *map);
+
bool anv_nir_add_base_work_group_id(nir_shader *shader,
struct brw_cs_prog_data *prog_data);
--- /dev/null
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (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 "anv_nir.h"
+#include "compiler/brw_nir.h"
+
+void
+anv_compute_push_layout(const struct anv_physical_device *pdevice,
+ struct brw_stage_prog_data *prog_data,
+ struct anv_pipeline_bind_map *map)
+{
+ struct anv_push_range push_constant_range = {
+ .set = ANV_DESCRIPTOR_SET_PUSH_CONSTANTS,
+ .length = DIV_ROUND_UP(prog_data->nr_params, 8),
+ };
+
+ if (pdevice->info.gen >= 8 || pdevice->info.is_haswell) {
+ /* The Skylake PRM contains the following restriction:
+ *
+ * "The driver must ensure The following case does not occur
+ * without a flush to the 3D engine: 3DSTATE_CONSTANT_* with
+ * buffer 3 read length equal to zero committed followed by a
+ * 3DSTATE_CONSTANT_* with buffer 0 read length not equal to
+ * zero committed."
+ *
+ * To avoid this, we program the buffers in the highest slots.
+ * This way, slot 0 is only used if slot 3 is also used.
+ */
+ int n = 3;
+
+ for (int i = 3; i >= 0; i--) {
+ const struct brw_ubo_range *ubo_range = &prog_data->ubo_ranges[i];
+ if (ubo_range->length == 0)
+ continue;
+
+ const struct anv_pipeline_binding *binding =
+ &map->surface_to_descriptor[ubo_range->block];
+
+ map->push_ranges[n--] = (struct anv_push_range) {
+ .set = binding->set,
+ .index = binding->index,
+ .dynamic_offset_index = binding->dynamic_offset_index,
+ .start = ubo_range->start,
+ .length = ubo_range->length,
+ };
+ }
+
+ if (push_constant_range.length > 0)
+ map->push_ranges[n--] = push_constant_range;
+ } else {
+ /* For Ivy Bridge, the push constants packets have a different
+ * rule that would require us to iterate in the other direction
+ * and possibly mess around with dynamic state base address.
+ * Don't bother; just emit regular push constants at n = 0.
+ */
+ map->push_ranges[0] = push_constant_range;
+ }
+}
goto fail;
}
+ anv_compute_push_layout(&pipeline->device->instance->physicalDevice,
+ &stages[s].prog_data.base,
+ &stages[s].bind_map);
+
struct anv_shader_bin *bin =
anv_device_upload_kernel(pipeline->device, cache,
&stages[s].cache_key,
blob_write_bytes(blob, shader->bind_map.sampler_to_descriptor,
shader->bind_map.sampler_count *
sizeof(*shader->bind_map.sampler_to_descriptor));
+ blob_write_bytes(blob, shader->bind_map.push_ranges,
+ sizeof(shader->bind_map.push_ranges));
return !blob->out_of_memory;
}
bind_map.sampler_to_descriptor = (void *)
blob_read_bytes(blob, bind_map.sampler_count *
sizeof(*bind_map.sampler_to_descriptor));
+ blob_copy_bytes(blob, bind_map.push_ranges, sizeof(bind_map.push_ranges));
if (blob->overrun)
return NULL;
struct anv_descriptor_pool *pool,
struct anv_descriptor_set *set);
+#define ANV_DESCRIPTOR_SET_PUSH_CONSTANTS (UINT8_MAX - 4)
#define ANV_DESCRIPTOR_SET_DESCRIPTORS (UINT8_MAX - 3)
#define ANV_DESCRIPTOR_SET_NUM_WORK_GROUPS (UINT8_MAX - 2)
#define ANV_DESCRIPTOR_SET_SHADER_CONSTANTS (UINT8_MAX - 1)
bool write_only;
};
+struct anv_push_range {
+ /** Index in the descriptor set */
+ uint32_t index;
+
+ /** Descriptor set index */
+ uint8_t set;
+
+ /** Dynamic offset index (for dynamic UBOs) */
+ uint8_t dynamic_offset_index;
+
+ /** Start offset in units of 32B */
+ uint8_t start;
+
+ /** Range in units of 32B */
+ uint8_t length;
+};
+
struct anv_pipeline_layout {
struct {
struct anv_descriptor_set_layout *layout;
struct anv_pipeline_binding * surface_to_descriptor;
struct anv_pipeline_binding * sampler_to_descriptor;
+
+ struct anv_push_range push_ranges[4];
};
struct anv_shader_bin_key {
c._3DCommandSubOpcode = push_constant_opcodes[stage];
if (anv_pipeline_has_stage(pipeline, stage)) {
-#if GEN_GEN >= 8 || GEN_IS_HASWELL
- const struct brw_stage_prog_data *prog_data =
- pipeline->shaders[stage]->prog_data;
const struct anv_pipeline_bind_map *bind_map =
&pipeline->shaders[stage]->bind_map;
- /* The Skylake PRM contains the following restriction:
- *
- * "The driver must ensure The following case does not occur
- * without a flush to the 3D engine: 3DSTATE_CONSTANT_* with
- * buffer 3 read length equal to zero committed followed by a
- * 3DSTATE_CONSTANT_* with buffer 0 read length not equal to
- * zero committed."
- *
- * To avoid this, we program the buffers in the highest slots.
- * This way, slot 0 is only used if slot 3 is also used.
- */
- int n = 3;
-
- for (int i = 3; i >= 0; i--) {
- const struct brw_ubo_range *range = &prog_data->ubo_ranges[i];
+ for (unsigned i = 0; i < 4; i++) {
+ const struct anv_push_range *range = &bind_map->push_ranges[i];
if (range->length == 0)
continue;
- const unsigned surface =
- prog_data->binding_table.ubo_start + range->block;
-
- assert(surface <= bind_map->surface_count);
- const struct anv_pipeline_binding *binding =
- &bind_map->surface_to_descriptor[surface];
-
struct anv_address addr;
- if (binding->set == ANV_DESCRIPTOR_SET_DESCRIPTORS) {
+ switch (range->set) {
+ case ANV_DESCRIPTOR_SET_DESCRIPTORS: {
/* This is a descriptor set buffer so the set index is
* actually given by binding->binding. (Yes, that's
* confusing.)
*/
struct anv_descriptor_set *set =
- gfx_state->base.descriptors[binding->index];
-
+ gfx_state->base.descriptors[range->index];
addr = anv_descriptor_set_address(cmd_buffer, set);
- } else {
- assert(binding->set < MAX_SETS);
+ break;
+ }
+
+ case ANV_DESCRIPTOR_SET_PUSH_CONSTANTS: {
+ struct anv_state state =
+ anv_cmd_buffer_push_constants(cmd_buffer, stage);
+ addr = (struct anv_address) {
+ .bo = cmd_buffer->device->dynamic_state_pool.block_pool.bo,
+ .offset = state.offset,
+ };
+ break;
+ }
+
+ default: {
+ assert(range->set < MAX_SETS);
struct anv_descriptor_set *set =
- gfx_state->base.descriptors[binding->set];
+ gfx_state->base.descriptors[range->set];
const struct anv_descriptor *desc =
- &set->descriptors[binding->index];
+ &set->descriptors[range->index];
if (desc->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
addr = desc->buffer_view->address;
} else {
assert(desc->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
-
uint32_t dynamic_offset =
- gfx_state->base.dynamic_offsets[binding->dynamic_offset_index];
+ gfx_state->base.dynamic_offsets[range->dynamic_offset_index];
addr = anv_address_add(desc->buffer->address,
desc->offset + dynamic_offset);
}
}
+ }
- c.ConstantBody.Buffer[n] =
+ c.ConstantBody.ReadLength[i] = range->length;
+ c.ConstantBody.Buffer[i] =
anv_address_add(addr, range->start * 32);
- c.ConstantBody.ReadLength[n] = range->length;
- n--;
- }
-
- struct anv_state state =
- anv_cmd_buffer_push_constants(cmd_buffer, stage);
-
- if (state.alloc_size > 0) {
- c.ConstantBody.Buffer[n] = (struct anv_address) {
- .bo = cmd_buffer->device->dynamic_state_pool.block_pool.bo,
- .offset = state.offset,
- };
- c.ConstantBody.ReadLength[n] =
- DIV_ROUND_UP(state.alloc_size, 32);
}
-#else
- /* For Ivy Bridge, the push constants packets have a different
- * rule that would require us to iterate in the other direction
- * and possibly mess around with dynamic state base address.
- * Don't bother; just emit regular push constants at n = 0.
- */
- struct anv_state state =
- anv_cmd_buffer_push_constants(cmd_buffer, stage);
-
- if (state.alloc_size > 0) {
- c.ConstantBody.Buffer[0].offset = state.offset,
- c.ConstantBody.ReadLength[0] =
- DIV_ROUND_UP(state.alloc_size, 32);
- }
-#endif
}
}
'anv_nir.h',
'anv_nir_add_base_work_group_id.c',
'anv_nir_apply_pipeline_layout.c',
+ 'anv_nir_compute_push_layout.c',
'anv_nir_lower_multiview.c',
'anv_nir_lower_push_constants.c',
'anv_nir_lower_ycbcr_textures.c',