#include "common/gen_l3_config.h"
#include "common/gen_sample_positions.h"
+#include "vk_util.h"
#include "vk_format_info.h"
static uint32_t
const uint32_t num_dwords = 1 + total_elems * 2;
p = anv_batch_emitn(&pipeline->batch, num_dwords,
GENX(3DSTATE_VERTEX_ELEMENTS));
+ if (!p)
+ return;
memset(p + 1, 0, (num_dwords - 1) * 4);
for (uint32_t i = 0; i < info->vertexAttributeDescriptionCount; i++) {
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_VF_INSTANCING), vfi) {
vfi.InstancingEnable = pipeline->instancing_enable[desc->binding];
vfi.VertexElementIndex = slot;
- /* Vulkan so far doesn't have an instance divisor, so
- * this is always 1 (ignored if not instancing). */
- vfi.InstanceDataStepRate = 1;
+ /* Our implementation of VK_KHR_multiview uses instancing to draw
+ * the different views. If the client asks for instancing, we
+ * need to use the Instance Data Step Rate to ensure that we
+ * repeat the client's per-instance data once for each view.
+ */
+ vfi.InstanceDataStepRate = anv_subpass_view_count(pipeline->subpass);
}
#endif
}
}
}
-static inline void
+static void
emit_urb_setup(struct anv_pipeline *pipeline)
{
unsigned entry_size[4];
/* We have to subtract two slots to accout for the URB entry output
* read offset in the VS and GS stages.
*/
- assert(slot >= 2);
const int source_attr = slot - 2 * urb_entry_read_offset;
+ assert(source_attr >= 0 && source_attr < 32);
max_source_attr = MAX2(max_source_attr, source_attr);
swiz.Attribute[input_index].SourceAttribute = source_attr;
}
uint32_t *dw = anv_batch_emit_dwords(&pipeline->batch,
GENX(3DSTATE_SBE_length));
+ if (!dw)
+ return;
GENX(3DSTATE_SBE_pack)(&pipeline->batch, dw, &sbe);
#if GEN_GEN >= 8
dw = anv_batch_emit_dwords(&pipeline->batch, GENX(3DSTATE_SBE_SWIZ_length));
+ if (!dw)
+ return;
GENX(3DSTATE_SBE_SWIZ_pack)(&pipeline->batch, dw, &swiz);
#endif
}
*/
#if GEN_GEN >= 8
raster.DXMultisampleRasterizationEnable = true;
+ /* NOTE: 3DSTATE_RASTER::ForcedSampleCount affects the BDW and SKL PMA fix
+ * computations. If we ever set this bit to a different value, they will
+ * need to be updated accordingly.
+ */
raster.ForcedSampleCount = FSC_NUMRASTSAMPLES_0;
raster.ForceMultisampling = false;
#else
/* Gen7 requires that we provide the depth format in 3DSTATE_SF so that it
* can get the depth offsets correct.
*/
- if (subpass->depth_stencil_attachment < pass->attachment_count) {
+ if (subpass->depth_stencil_attachment.attachment < pass->attachment_count) {
VkFormat vk_format =
- pass->attachments[subpass->depth_stencil_attachment].format;
+ pass->attachments[subpass->depth_stencil_attachment.attachment].format;
assert(vk_format_is_depth_or_stencil(vk_format));
if (vk_format_aspects(vk_format) & VK_IMAGE_ASPECT_DEPTH_BIT) {
enum isl_format isl_format =
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_MULTISAMPLE), ms) {
ms.NumberofMultisamples = log2_samples;
+ ms.PixelLocation = CENTER;
#if GEN_GEN >= 8
/* The PRM says that this bit is valid only for DX9:
*
* should not have any effect by setting or not setting this bit.
*/
ms.PixelPositionOffsetEnable = false;
- ms.PixelLocation = CENTER;
#else
- ms.PixelLocation = PIXLOC_CENTER;
switch (samples) {
case 1:
[VK_STENCIL_OP_DECREMENT_AND_WRAP] = STENCILOP_DECR,
};
+/* This function sanitizes the VkStencilOpState by looking at the compare ops
+ * and trying to determine whether or not a given stencil op can ever actually
+ * occur. Stencil ops which can never occur are set to VK_STENCIL_OP_KEEP.
+ * This function returns true if, after sanitation, any of the stencil ops are
+ * set to something other than VK_STENCIL_OP_KEEP.
+ */
+static bool
+sanitize_stencil_face(VkStencilOpState *face,
+ VkCompareOp depthCompareOp)
+{
+ /* If compareOp is ALWAYS then the stencil test will never fail and failOp
+ * will never happen. Set failOp to KEEP in this case.
+ */
+ if (face->compareOp == VK_COMPARE_OP_ALWAYS)
+ face->failOp = VK_STENCIL_OP_KEEP;
+
+ /* If compareOp is NEVER or depthCompareOp is NEVER then one of the depth
+ * or stencil tests will fail and passOp will never happen.
+ */
+ if (face->compareOp == VK_COMPARE_OP_NEVER ||
+ depthCompareOp == VK_COMPARE_OP_NEVER)
+ face->passOp = VK_STENCIL_OP_KEEP;
+
+ /* If compareOp is NEVER or depthCompareOp is ALWAYS then either the
+ * stencil test will fail or the depth test will pass. In either case,
+ * depthFailOp will never happen.
+ */
+ if (face->compareOp == VK_COMPARE_OP_NEVER ||
+ depthCompareOp == VK_COMPARE_OP_ALWAYS)
+ face->depthFailOp = VK_STENCIL_OP_KEEP;
+
+ return face->failOp != VK_STENCIL_OP_KEEP ||
+ face->depthFailOp != VK_STENCIL_OP_KEEP ||
+ face->passOp != VK_STENCIL_OP_KEEP;
+}
+
+/* Intel hardware is fairly sensitive to whether or not depth/stencil writes
+ * are enabled. In the presence of discards, it's fairly easy to get into the
+ * non-promoted case which means a fairly big performance hit. From the Iron
+ * Lake PRM, Vol 2, pt. 1, section 8.4.3.2, "Early Depth Test Cases":
+ *
+ * "Non-promoted depth (N) is active whenever the depth test can be done
+ * early but it cannot determine whether or not to write source depth to
+ * the depth buffer, therefore the depth write must be performed post pixel
+ * shader. This includes cases where the pixel shader can kill pixels,
+ * including via sampler chroma key, as well as cases where the alpha test
+ * function is enabled, which kills pixels based on a programmable alpha
+ * test. In this case, even if the depth test fails, the pixel cannot be
+ * killed if a stencil write is indicated. Whether or not the stencil write
+ * happens depends on whether or not the pixel is killed later. In these
+ * cases if stencil test fails and stencil writes are off, the pixels can
+ * also be killed early. If stencil writes are enabled, the pixels must be
+ * treated as Computed depth (described above)."
+ *
+ * The same thing as mentioned in the stencil case can happen in the depth
+ * case as well if it thinks it writes depth but, thanks to the depth test
+ * being GL_EQUAL, the write doesn't actually matter. A little extra work
+ * up-front to try and disable depth and stencil writes can make a big
+ * difference.
+ *
+ * Unfortunately, the way depth and stencil testing is specified, there are
+ * many case where, regardless of depth/stencil writes being enabled, nothing
+ * actually gets written due to some other bit of state being set. This
+ * function attempts to "sanitize" the depth stencil state and disable writes
+ * and sometimes even testing whenever possible.
+ */
+static void
+sanitize_ds_state(VkPipelineDepthStencilStateCreateInfo *state,
+ bool *stencilWriteEnable,
+ VkImageAspectFlags ds_aspects)
+{
+ *stencilWriteEnable = state->stencilTestEnable;
+
+ /* If the depth test is disabled, we won't be writing anything. */
+ if (!state->depthTestEnable)
+ state->depthWriteEnable = false;
+
+ /* The Vulkan spec requires that if either depth or stencil is not present,
+ * the pipeline is to act as if the test silently passes.
+ */
+ if (!(ds_aspects & VK_IMAGE_ASPECT_DEPTH_BIT)) {
+ state->depthWriteEnable = false;
+ state->depthCompareOp = VK_COMPARE_OP_ALWAYS;
+ }
+
+ if (!(ds_aspects & VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ *stencilWriteEnable = false;
+ state->front.compareOp = VK_COMPARE_OP_ALWAYS;
+ state->back.compareOp = VK_COMPARE_OP_ALWAYS;
+ }
+
+ /* If the stencil test is enabled and always fails, then we will never get
+ * to the depth test so we can just disable the depth test entirely.
+ */
+ if (state->stencilTestEnable &&
+ state->front.compareOp == VK_COMPARE_OP_NEVER &&
+ state->back.compareOp == VK_COMPARE_OP_NEVER) {
+ state->depthTestEnable = false;
+ state->depthWriteEnable = false;
+ }
+
+ /* If depthCompareOp is EQUAL then the value we would be writing to the
+ * depth buffer is the same as the value that's already there so there's no
+ * point in writing it.
+ */
+ if (state->depthCompareOp == VK_COMPARE_OP_EQUAL)
+ state->depthWriteEnable = false;
+
+ /* If the stencil ops are such that we don't actually ever modify the
+ * stencil buffer, we should disable writes.
+ */
+ if (!sanitize_stencil_face(&state->front, state->depthCompareOp) &&
+ !sanitize_stencil_face(&state->back, state->depthCompareOp))
+ *stencilWriteEnable = false;
+
+ /* If the depth test always passes and we never write out depth, that's the
+ * same as if the depth test is disabled entirely.
+ */
+ if (state->depthCompareOp == VK_COMPARE_OP_ALWAYS &&
+ !state->depthWriteEnable)
+ state->depthTestEnable = false;
+
+ /* If the stencil test always passes and we never write out stencil, that's
+ * the same as if the stencil test is disabled entirely.
+ */
+ if (state->front.compareOp == VK_COMPARE_OP_ALWAYS &&
+ state->back.compareOp == VK_COMPARE_OP_ALWAYS &&
+ !*stencilWriteEnable)
+ state->stencilTestEnable = false;
+}
+
static void
emit_ds_state(struct anv_pipeline *pipeline,
- const VkPipelineDepthStencilStateCreateInfo *info,
+ const VkPipelineDepthStencilStateCreateInfo *pCreateInfo,
const struct anv_render_pass *pass,
const struct anv_subpass *subpass)
{
# define depth_stencil_dw pipeline->gen9.wm_depth_stencil
#endif
- if (info == NULL) {
+ if (pCreateInfo == NULL) {
/* We're going to OR this together with the dynamic state. We need
* to make sure it's initialized to something useful.
*/
+ pipeline->writes_stencil = false;
+ pipeline->stencil_test_enable = false;
+ pipeline->writes_depth = false;
+ pipeline->depth_test_enable = false;
memset(depth_stencil_dw, 0, sizeof(depth_stencil_dw));
return;
}
+ VkImageAspectFlags ds_aspects = 0;
+ if (subpass->depth_stencil_attachment.attachment != VK_ATTACHMENT_UNUSED) {
+ VkFormat depth_stencil_format =
+ pass->attachments[subpass->depth_stencil_attachment.attachment].format;
+ ds_aspects = vk_format_aspects(depth_stencil_format);
+ }
+
+ VkPipelineDepthStencilStateCreateInfo info = *pCreateInfo;
+ sanitize_ds_state(&info, &pipeline->writes_stencil, ds_aspects);
+ pipeline->stencil_test_enable = info.stencilTestEnable;
+ pipeline->writes_depth = info.depthWriteEnable;
+ pipeline->depth_test_enable = info.depthTestEnable;
+
/* VkBool32 depthBoundsTestEnable; // optional (depth_bounds_test) */
#if GEN_GEN <= 7
#else
struct GENX(3DSTATE_WM_DEPTH_STENCIL) depth_stencil = {
#endif
- .DepthTestEnable = info->depthTestEnable,
- .DepthBufferWriteEnable = info->depthWriteEnable,
- .DepthTestFunction = vk_to_gen_compare_op[info->depthCompareOp],
+ .DepthTestEnable = info.depthTestEnable,
+ .DepthBufferWriteEnable = info.depthWriteEnable,
+ .DepthTestFunction = vk_to_gen_compare_op[info.depthCompareOp],
.DoubleSidedStencilEnable = true,
- .StencilTestEnable = info->stencilTestEnable,
- .StencilBufferWriteEnable = info->stencilTestEnable,
- .StencilFailOp = vk_to_gen_stencil_op[info->front.failOp],
- .StencilPassDepthPassOp = vk_to_gen_stencil_op[info->front.passOp],
- .StencilPassDepthFailOp = vk_to_gen_stencil_op[info->front.depthFailOp],
- .StencilTestFunction = vk_to_gen_compare_op[info->front.compareOp],
- .BackfaceStencilFailOp = vk_to_gen_stencil_op[info->back.failOp],
- .BackfaceStencilPassDepthPassOp = vk_to_gen_stencil_op[info->back.passOp],
- .BackfaceStencilPassDepthFailOp =vk_to_gen_stencil_op[info->back.depthFailOp],
- .BackfaceStencilTestFunction = vk_to_gen_compare_op[info->back.compareOp],
+ .StencilTestEnable = info.stencilTestEnable,
+ .StencilFailOp = vk_to_gen_stencil_op[info.front.failOp],
+ .StencilPassDepthPassOp = vk_to_gen_stencil_op[info.front.passOp],
+ .StencilPassDepthFailOp = vk_to_gen_stencil_op[info.front.depthFailOp],
+ .StencilTestFunction = vk_to_gen_compare_op[info.front.compareOp],
+ .BackfaceStencilFailOp = vk_to_gen_stencil_op[info.back.failOp],
+ .BackfaceStencilPassDepthPassOp = vk_to_gen_stencil_op[info.back.passOp],
+ .BackfaceStencilPassDepthFailOp =vk_to_gen_stencil_op[info.back.depthFailOp],
+ .BackfaceStencilTestFunction = vk_to_gen_compare_op[info.back.compareOp],
};
- VkImageAspectFlags aspects = 0;
- if (subpass->depth_stencil_attachment != VK_ATTACHMENT_UNUSED) {
- VkFormat depth_stencil_format =
- pass->attachments[subpass->depth_stencil_attachment].format;
- aspects = vk_format_aspects(depth_stencil_format);
- }
-
- /* The Vulkan spec requires that if either depth or stencil is not present,
- * the pipeline is to act as if the test silently passes.
- */
- if (!(aspects & VK_IMAGE_ASPECT_DEPTH_BIT)) {
- depth_stencil.DepthBufferWriteEnable = false;
- depth_stencil.DepthTestFunction = PREFILTEROPALWAYS;
- }
-
- if (!(aspects & VK_IMAGE_ASPECT_STENCIL_BIT)) {
- depth_stencil.StencilBufferWriteEnable = false;
- depth_stencil.StencilTestFunction = PREFILTEROPALWAYS;
- depth_stencil.BackfaceStencilTestFunction = PREFILTEROPALWAYS;
- }
-
- /* From the Broadwell PRM:
- *
- * "If Depth_Test_Enable = 1 AND Depth_Test_func = EQUAL, the
- * Depth_Write_Enable must be set to 0."
- */
- if (info->depthTestEnable && info->depthCompareOp == VK_COMPARE_OP_EQUAL)
- depth_stencil.DepthBufferWriteEnable = false;
-
#if GEN_GEN <= 7
GENX(DEPTH_STENCIL_STATE_pack)(NULL, depth_stencil_dw, &depth_stencil);
#else
{
struct anv_device *device = pipeline->device;
- const uint32_t num_dwords = GENX(BLEND_STATE_length);
- pipeline->blend_state =
- anv_state_pool_alloc(&device->dynamic_state_pool, num_dwords * 4, 64);
struct GENX(BLEND_STATE) blend_state = {
#if GEN_GEN >= 8
.AlphaToCoverageEnable = ms_info && ms_info->alphaToCoverageEnable,
.AlphaToOneEnable = ms_info && ms_info->alphaToOneEnable,
-#else
- /* Make sure it gets zeroed */
- .Entry = { { 0, }, },
#endif
};
- /* Default everything to disabled */
- for (uint32_t i = 0; i < 8; i++) {
- blend_state.Entry[i].WriteDisableAlpha = true;
- blend_state.Entry[i].WriteDisableRed = true;
- blend_state.Entry[i].WriteDisableGreen = true;
- blend_state.Entry[i].WriteDisableBlue = true;
- }
-
uint32_t surface_count = 0;
struct anv_pipeline_bind_map *map;
if (anv_pipeline_has_stage(pipeline, MESA_SHADER_FRAGMENT)) {
surface_count = map->surface_count;
}
+ const uint32_t num_dwords = GENX(BLEND_STATE_length) +
+ GENX(BLEND_STATE_ENTRY_length) * surface_count;
+ pipeline->blend_state =
+ anv_state_pool_alloc(&device->dynamic_state_pool, num_dwords * 4, 64);
+
bool has_writeable_rt = false;
+ uint32_t *state_pos = pipeline->blend_state.map;
+ state_pos += GENX(BLEND_STATE_length);
+#if GEN_GEN >= 8
+ struct GENX(BLEND_STATE_ENTRY) bs0 = { 0 };
+#endif
for (unsigned i = 0; i < surface_count; i++) {
struct anv_pipeline_binding *binding = &map->surface_to_descriptor[i];
/* We can have at most 8 attachments */
assert(i < 8);
- if (binding->index >= info->attachmentCount)
+ if (info == NULL || binding->index >= info->attachmentCount) {
+ /* Default everything to disabled */
+ struct GENX(BLEND_STATE_ENTRY) entry = {
+ .WriteDisableAlpha = true,
+ .WriteDisableRed = true,
+ .WriteDisableGreen = true,
+ .WriteDisableBlue = true,
+ };
+ GENX(BLEND_STATE_ENTRY_pack)(NULL, state_pos, &entry);
+ state_pos += GENX(BLEND_STATE_ENTRY_length);
continue;
+ }
assert(binding->binding == 0);
const VkPipelineColorBlendAttachmentState *a =
&info->pAttachments[binding->index];
- blend_state.Entry[i] = (struct GENX(BLEND_STATE_ENTRY)) {
+ struct GENX(BLEND_STATE_ENTRY) entry = {
#if GEN_GEN < 8
.AlphaToCoverageEnable = ms_info && ms_info->alphaToCoverageEnable,
.AlphaToOneEnable = ms_info && ms_info->alphaToOneEnable,
#if GEN_GEN >= 8
blend_state.IndependentAlphaBlendEnable = true;
#else
- blend_state.Entry[i].IndependentAlphaBlendEnable = true;
+ entry.IndependentAlphaBlendEnable = true;
#endif
}
*/
if (a->colorBlendOp == VK_BLEND_OP_MIN ||
a->colorBlendOp == VK_BLEND_OP_MAX) {
- blend_state.Entry[i].SourceBlendFactor = BLENDFACTOR_ONE;
- blend_state.Entry[i].DestinationBlendFactor = BLENDFACTOR_ONE;
+ entry.SourceBlendFactor = BLENDFACTOR_ONE;
+ entry.DestinationBlendFactor = BLENDFACTOR_ONE;
}
if (a->alphaBlendOp == VK_BLEND_OP_MIN ||
a->alphaBlendOp == VK_BLEND_OP_MAX) {
- blend_state.Entry[i].SourceAlphaBlendFactor = BLENDFACTOR_ONE;
- blend_state.Entry[i].DestinationAlphaBlendFactor = BLENDFACTOR_ONE;
+ entry.SourceAlphaBlendFactor = BLENDFACTOR_ONE;
+ entry.DestinationAlphaBlendFactor = BLENDFACTOR_ONE;
}
+ GENX(BLEND_STATE_ENTRY_pack)(NULL, state_pos, &entry);
+ state_pos += GENX(BLEND_STATE_ENTRY_length);
+#if GEN_GEN >= 8
+ if (i == 0)
+ bs0 = entry;
+#endif
}
#if GEN_GEN >= 8
- struct GENX(BLEND_STATE_ENTRY) *bs0 = &blend_state.Entry[0];
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_PS_BLEND), blend) {
blend.AlphaToCoverageEnable = blend_state.AlphaToCoverageEnable;
blend.HasWriteableRT = has_writeable_rt;
- blend.ColorBufferBlendEnable = bs0->ColorBufferBlendEnable;
- blend.SourceAlphaBlendFactor = bs0->SourceAlphaBlendFactor;
- blend.DestinationAlphaBlendFactor = bs0->DestinationAlphaBlendFactor;
- blend.SourceBlendFactor = bs0->SourceBlendFactor;
- blend.DestinationBlendFactor = bs0->DestinationBlendFactor;
+ blend.ColorBufferBlendEnable = bs0.ColorBufferBlendEnable;
+ blend.SourceAlphaBlendFactor = bs0.SourceAlphaBlendFactor;
+ blend.DestinationAlphaBlendFactor = bs0.DestinationAlphaBlendFactor;
+ blend.SourceBlendFactor = bs0.SourceBlendFactor;
+ blend.DestinationBlendFactor = bs0.DestinationBlendFactor;
blend.AlphaTestEnable = false;
blend.IndependentAlphaBlendEnable =
blend_state.IndependentAlphaBlendEnable;
#endif
GENX(BLEND_STATE_pack)(NULL, pipeline->blend_state.map, &blend_state);
- if (!device->info.has_llc)
- anv_state_clflush(pipeline->blend_state);
+ anv_state_flush(device, pipeline->blend_state);
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_BLEND_STATE_POINTERS), bsp) {
bsp.BlendStatePointer = pipeline->blend_state.offset;
(void) wm_prog_data;
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_CLIP), clip) {
clip.ClipEnable = true;
+ clip.StatisticsEnable = true;
clip.EarlyCullEnable = true;
clip.APIMode = APIMODE_D3D,
clip.ViewportXYClipTestEnable = true;
clip.MinimumPointWidth = 0.125;
clip.MaximumPointWidth = 255.875;
- clip.MaximumVPIndex = (vp_info ? vp_info->viewportCount : 1) - 1;
+
+ const struct brw_vue_prog_data *last =
+ anv_pipeline_get_last_vue_prog_data(pipeline);
+
+ /* From the Vulkan 1.0.45 spec:
+ *
+ * "If the last active vertex processing stage shader entry point's
+ * interface does not include a variable decorated with
+ * ViewportIndex, then the first viewport is used."
+ */
+ if (vp_info && (last->vue_map.slots_valid & VARYING_BIT_VIEWPORT)) {
+ clip.MaximumVPIndex = vp_info->viewportCount - 1;
+ } else {
+ clip.MaximumVPIndex = 0;
+ }
+
+ /* From the Vulkan 1.0.45 spec:
+ *
+ * "If the last active vertex processing stage shader entry point's
+ * interface does not include a variable decorated with Layer, then
+ * the first layer is used."
+ */
+ clip.ForceZeroRTAIndexEnable =
+ !(last->vue_map.slots_valid & VARYING_BIT_LAYER);
#if GEN_GEN == 7
clip.FrontWinding = vk_to_gen_front_face[rs_info->frontFace];
clip.CullMode = vk_to_gen_cullmode[rs_info->cullMode];
clip.ViewportZClipTestEnable = !pipeline->depth_clamp_enable;
- const struct brw_vue_prog_data *last =
- anv_pipeline_get_last_vue_prog_data(pipeline);
if (last) {
clip.UserClipDistanceClipTestEnableBitmask = last->clip_distance_mask;
clip.UserClipDistanceCullTestEnableBitmask = last->cull_distance_mask;
}
#else
clip.NonPerspectiveBarycentricEnable = wm_prog_data ?
- (wm_prog_data->barycentric_interp_modes & 0x38) != 0 : 0;
+ (wm_prog_data->barycentric_interp_modes &
+ BRW_BARYCENTRIC_NONPERSPECTIVE_BITS) != 0 : 0;
#endif
}
}
}
}
-static inline uint32_t
+static uint32_t
get_sampler_count(const struct anv_shader_bin *bin)
{
- return DIV_ROUND_UP(bin->bind_map.sampler_count, 4);
+ uint32_t count_by_4 = DIV_ROUND_UP(bin->bind_map.sampler_count, 4);
+
+ /* We can potentially have way more than 32 samplers and that's ok.
+ * However, the 3DSTATE_XS packets only have 3 bits to specify how
+ * many to pre-fetch and all values above 4 are marked reserved.
+ */
+ return MIN2(count_by_4, 4);
}
-static inline uint32_t
+static uint32_t
get_binding_table_entry_count(const struct anv_shader_bin *bin)
{
return DIV_ROUND_UP(bin->bind_map.surface_count, 32);
}
-static inline struct anv_address
+static struct anv_address
get_scratch_address(struct anv_pipeline *pipeline,
gl_shader_stage stage,
const struct anv_shader_bin *bin)
};
}
-static inline uint32_t
+static uint32_t
get_scratch_space(const struct anv_shader_bin *bin)
{
return ffs(bin->prog_data->total_scratch / 2048);
}
-static inline uint32_t
-get_urb_output_offset()
-{
- /* Skip the VUE header and position slots */
- return 1;
-}
-
-static inline uint32_t
-get_urb_output_length(const struct anv_shader_bin *bin)
-{
- const struct brw_vue_prog_data *prog_data =
- (const struct brw_vue_prog_data *)bin->prog_data;
-
- return (prog_data->vue_map.num_slots + 1) / 2 - get_urb_output_offset();
-}
-
static void
emit_3dstate_vs(struct anv_pipeline *pipeline)
{
assert(anv_pipeline_has_stage(pipeline, MESA_SHADER_VERTEX));
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_VS), vs) {
- vs.FunctionEnable = true;
+ vs.Enable = true;
vs.StatisticsEnable = true;
vs.KernelStartPointer = vs_bin->kernel.offset;
#if GEN_GEN >= 8
#endif
assert(!vs_prog_data->base.base.use_alt_mode);
+#if GEN_GEN < 11
vs.SingleVertexDispatch = false;
+#endif
vs.VectorMaskEnable = false;
vs.SamplerCount = get_sampler_count(vs_bin);
vs.BindingTableEntryCount = get_binding_table_entry_count(vs_bin);
vs_prog_data->base.base.dispatch_grf_start_reg;
#if GEN_GEN >= 8
- vs.VertexURBEntryOutputReadOffset = get_urb_output_offset();
- vs.VertexURBEntryOutputLength = get_urb_output_length(vs_bin);
-
vs.UserClipDistanceClipTestEnableBitmask =
vs_prog_data->base.clip_distance_mask;
vs.UserClipDistanceCullTestEnableBitmask =
}
static void
-emit_3dstate_hs_te_ds(struct anv_pipeline *pipeline)
+emit_3dstate_hs_te_ds(struct anv_pipeline *pipeline,
+ const VkPipelineTessellationStateCreateInfo *tess_info)
{
if (!anv_pipeline_has_stage(pipeline, MESA_SHADER_TESS_EVAL)) {
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_HS), hs);
const struct brw_tes_prog_data *tes_prog_data = get_tes_prog_data(pipeline);
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_HS), hs) {
- hs.FunctionEnable = true;
+ hs.Enable = true;
hs.StatisticsEnable = true;
hs.KernelStartPointer = tcs_bin->kernel.offset;
get_scratch_address(pipeline, MESA_SHADER_TESS_CTRL, tcs_bin);
}
+ const VkPipelineTessellationDomainOriginStateCreateInfoKHR *domain_origin_state =
+ tess_info ? vk_find_struct_const(tess_info, PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR) : NULL;
+
+ VkTessellationDomainOriginKHR uv_origin =
+ domain_origin_state ? domain_origin_state->domainOrigin :
+ VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR;
+
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_TE), te) {
te.Partitioning = tes_prog_data->partitioning;
- te.OutputTopology = tes_prog_data->output_topology;
+
+ if (uv_origin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR) {
+ te.OutputTopology = tes_prog_data->output_topology;
+ } else {
+ /* When the origin is upper-left, we have to flip the winding order */
+ if (tes_prog_data->output_topology == OUTPUT_TRI_CCW) {
+ te.OutputTopology = OUTPUT_TRI_CW;
+ } else if (tes_prog_data->output_topology == OUTPUT_TRI_CW) {
+ te.OutputTopology = OUTPUT_TRI_CCW;
+ } else {
+ te.OutputTopology = tes_prog_data->output_topology;
+ }
+ }
+
te.TEDomain = tes_prog_data->domain;
te.TEEnable = true;
te.MaximumTessellationFactorOdd = 63.0;
}
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_DS), ds) {
- ds.FunctionEnable = true;
+ ds.Enable = true;
ds.StatisticsEnable = true;
ds.KernelStartPointer = tes_bin->kernel.offset;
tes_prog_data->base.base.dispatch_grf_start_reg;
#if GEN_GEN >= 8
- ds.VertexURBEntryOutputReadOffset = 1;
- ds.VertexURBEntryOutputLength =
- (tes_prog_data->base.vue_map.num_slots + 1) / 2 - 1;
-
+#if GEN_GEN < 11
ds.DispatchMode =
tes_prog_data->base.dispatch_mode == DISPATCH_MODE_SIMD8 ?
DISPATCH_MODE_SIMD8_SINGLE_PATCH :
DISPATCH_MODE_SIMD4X2;
+#else
+ assert(tes_prog_data->base.dispatch_mode == DISPATCH_MODE_SIMD8);
+ ds.DispatchMode = DISPATCH_MODE_SIMD8_SINGLE_PATCH;
+#endif
ds.UserClipDistanceClipTestEnableBitmask =
tes_prog_data->base.clip_distance_mask;
const struct brw_gs_prog_data *gs_prog_data = get_gs_prog_data(pipeline);
anv_batch_emit(&pipeline->batch, GENX(3DSTATE_GS), gs) {
- gs.FunctionEnable = true;
+ gs.Enable = true;
gs.StatisticsEnable = true;
gs.KernelStartPointer = gs_bin->kernel.offset;
gs.DispatchMode = gs_prog_data->base.dispatch_mode;
gs.ControlDataFormat = gs_prog_data->control_data_format;
gs.ControlDataHeaderSize = gs_prog_data->control_data_header_size_hwords;
gs.InstanceControl = MAX2(gs_prog_data->invocations, 1) - 1;
-#if GEN_GEN >= 8 || GEN_IS_HASWELL
gs.ReorderMode = TRAILING;
-#else
- gs.ReorderEnable = true;
-#endif
#if GEN_GEN >= 8
gs.ExpectedVertexCount = gs_prog_data->vertices_in;
gs_prog_data->base.base.dispatch_grf_start_reg;
#if GEN_GEN >= 8
- gs.VertexURBEntryOutputReadOffset = get_urb_output_offset();
- gs.VertexURBEntryOutputLength = get_urb_output_length(gs_bin);
-
gs.UserClipDistanceClipTestEnableBitmask =
gs_prog_data->base.clip_distance_mask;
gs.UserClipDistanceCullTestEnableBitmask =
}
}
-static inline bool
-has_color_buffer_write_enabled(const struct anv_pipeline *pipeline)
+static bool
+has_color_buffer_write_enabled(const struct anv_pipeline *pipeline,
+ const VkPipelineColorBlendStateCreateInfo *blend)
{
const struct anv_shader_bin *shader_bin =
pipeline->shaders[MESA_SHADER_FRAGMENT];
const struct anv_pipeline_bind_map *bind_map = &shader_bin->bind_map;
for (int i = 0; i < bind_map->surface_count; i++) {
- if (bind_map->surface_to_descriptor[i].set !=
- ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS)
+ struct anv_pipeline_binding *binding = &bind_map->surface_to_descriptor[i];
+
+ if (binding->set != ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS)
continue;
- if (bind_map->surface_to_descriptor[i].index != UINT8_MAX)
+
+ if (binding->index == UINT32_MAX)
+ continue;
+
+ if (blend->pAttachments[binding->index].colorWriteMask != 0)
return true;
}
static void
emit_3dstate_wm(struct anv_pipeline *pipeline, struct anv_subpass *subpass,
+ const VkPipelineColorBlendStateCreateInfo *blend,
const VkPipelineMultisampleStateCreateInfo *multisample)
{
const struct brw_wm_prog_data *wm_prog_data = get_wm_prog_data(pipeline);
if (wm.PixelShaderComputedDepthMode != PSCDEPTH_OFF ||
wm_prog_data->has_side_effects ||
wm.PixelShaderKillsPixel ||
- has_color_buffer_write_enabled(pipeline))
+ has_color_buffer_write_enabled(pipeline, blend))
wm.ThreadDispatchEnable = true;
if (samples > 1) {
}
}
-static inline bool
+UNUSED static bool
is_dual_src_blend_factor(VkBlendFactor factor)
{
return factor == VK_BLEND_FACTOR_SRC1_COLOR ||
* source blend factors.
*/
bool dual_src_blend = false;
- if (wm_prog_data->dual_src_blend) {
+ if (wm_prog_data->dual_src_blend && blend) {
for (uint32_t i = 0; i < blend->attachmentCount; i++) {
const VkPipelineColorBlendAttachmentState *bstate =
&blend->pAttachments[i];
ps.VectorMaskEnable = true;
ps.SamplerCount = get_sampler_count(fs_bin);
ps.BindingTableEntryCount = get_binding_table_entry_count(fs_bin);
- ps.PushConstantEnable = wm_prog_data->base.nr_params > 0;
+ ps.PushConstantEnable = wm_prog_data->base.nr_params > 0 ||
+ wm_prog_data->base.ubo_ranges[0].length;
ps.PositionXYOffsetSelect = wm_prog_data->uses_pos_offset ?
POSOFFSET_SAMPLE: POSOFFSET_NONE;
#if GEN_GEN < 8
#if GEN_GEN >= 8
static void
emit_3dstate_ps_extra(struct anv_pipeline *pipeline,
- struct anv_subpass *subpass)
+ struct anv_subpass *subpass,
+ const VkPipelineColorBlendStateCreateInfo *blend)
{
const struct brw_wm_prog_data *wm_prog_data = get_wm_prog_data(pipeline);
* attachments, we need to force-enable here.
*/
if ((wm_prog_data->has_side_effects || wm_prog_data->uses_kill) &&
- !has_color_buffer_write_enabled(pipeline))
+ !has_color_buffer_write_enabled(pipeline, blend))
ps.PixelShaderHasUAV = true;
#if GEN_GEN >= 9
}
#endif
+static void
+emit_3dstate_vf_statistics(struct anv_pipeline *pipeline)
+{
+ anv_batch_emit(&pipeline->batch, GENX(3DSTATE_VF_STATISTICS), vfs) {
+ vfs.StatisticsEnable = true;
+ }
+}
+
+static void
+compute_kill_pixel(struct anv_pipeline *pipeline,
+ const VkPipelineMultisampleStateCreateInfo *ms_info,
+ const struct anv_subpass *subpass)
+{
+ if (!anv_pipeline_has_stage(pipeline, MESA_SHADER_FRAGMENT)) {
+ pipeline->kill_pixel = false;
+ return;
+ }
+
+ const struct brw_wm_prog_data *wm_prog_data = get_wm_prog_data(pipeline);
+
+ /* This computes the KillPixel portion of the computation for whether or
+ * not we want to enable the PMA fix on gen8 or gen9. It's given by this
+ * chunk of the giant formula:
+ *
+ * (3DSTATE_PS_EXTRA::PixelShaderKillsPixels ||
+ * 3DSTATE_PS_EXTRA::oMask Present to RenderTarget ||
+ * 3DSTATE_PS_BLEND::AlphaToCoverageEnable ||
+ * 3DSTATE_PS_BLEND::AlphaTestEnable ||
+ * 3DSTATE_WM_CHROMAKEY::ChromaKeyKillEnable)
+ *
+ * 3DSTATE_WM_CHROMAKEY::ChromaKeyKillEnable is always false and so is
+ * 3DSTATE_PS_BLEND::AlphaTestEnable since Vulkan doesn't have a concept
+ * of an alpha test.
+ */
+ pipeline->kill_pixel =
+ subpass->has_ds_self_dep || wm_prog_data->uses_kill ||
+ wm_prog_data->uses_omask ||
+ (ms_info && ms_info->alphaToCoverageEnable);
+}
+
static VkResult
genX(graphics_pipeline_create)(
VkDevice _device,
emit_ds_state(pipeline, pCreateInfo->pDepthStencilState, pass, subpass);
emit_cb_state(pipeline, pCreateInfo->pColorBlendState,
pCreateInfo->pMultisampleState);
+ compute_kill_pixel(pipeline, pCreateInfo->pMultisampleState, subpass);
emit_urb_setup(pipeline);
* whole fixed function pipeline" means to emit a PIPE_CONTROL with the "CS
* Stall" bit set.
*/
- if (!brw->is_haswell && !brw->is_baytrail)
+ if (!device->info.is_haswell && !device->info.is_baytrail)
gen7_emit_vs_workaround_flush(brw);
#endif
emit_3dstate_vs(pipeline);
- emit_3dstate_hs_te_ds(pipeline);
+ emit_3dstate_hs_te_ds(pipeline, pCreateInfo->pTessellationState);
emit_3dstate_gs(pipeline);
emit_3dstate_sbe(pipeline);
- emit_3dstate_wm(pipeline, subpass, pCreateInfo->pMultisampleState);
+ emit_3dstate_wm(pipeline, subpass, pCreateInfo->pColorBlendState,
+ pCreateInfo->pMultisampleState);
emit_3dstate_ps(pipeline, pCreateInfo->pColorBlendState);
#if GEN_GEN >= 8
- emit_3dstate_ps_extra(pipeline, subpass);
+ emit_3dstate_ps_extra(pipeline, subpass, pCreateInfo->pColorBlendState);
emit_3dstate_vf_topology(pipeline);
#endif
+ emit_3dstate_vf_statistics(pipeline);
*pPipeline = anv_pipeline_to_handle(pipeline);
- return VK_SUCCESS;
+ return pipeline->batch.status;
}
static VkResult
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
pipeline->device = device;
- pipeline->layout = anv_pipeline_layout_from_handle(pCreateInfo->layout);
pipeline->blend_state.map = NULL;
pipeline->batch.next = pipeline->batch.start = pipeline->batch_data;
pipeline->batch.end = pipeline->batch.start + sizeof(pipeline->batch_data);
pipeline->batch.relocs = &pipeline->batch_relocs;
+ pipeline->batch.status = VK_SUCCESS;
/* When we free the pipeline, we detect stages based on the NULL status
* of various prog_data pointers. Make them NULL by default.
vfe.MaximumNumberofThreads =
devinfo->max_cs_threads * subslices - 1;
vfe.NumberofURBEntries = GEN_GEN <= 7 ? 0 : 2;
+#if GEN_GEN < 11
vfe.ResetGatewayTimer = true;
+#endif
#if GEN_GEN <= 8
vfe.BypassGatewayControl = true;
#endif
*pPipeline = anv_pipeline_to_handle(pipeline);
- return VK_SUCCESS;
+ return pipeline->batch.status;
}
VkResult genX(CreateGraphicsPipelines)(