PipelineCache: Better stencil support, and allow null pixel shaders.

This commit is contained in:
Dr. Chat
2016-07-24 15:36:41 -05:00
parent a065120793
commit b478408dfb
5 changed files with 355 additions and 42 deletions

View File

@@ -27,6 +27,7 @@ namespace vulkan {
using xe::ui::vulkan::CheckResult;
// Generated with `xenia-build genspirv`.
#include "xenia/gpu/vulkan/shaders/bin/dummy_frag.h"
#include "xenia/gpu/vulkan/shaders/bin/line_quad_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bin/point_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bin/quad_list_geom.h"
@@ -113,6 +114,13 @@ PipelineCache::PipelineCache(
err = vkCreateShaderModule(device_, &shader_module_info, nullptr,
&geometry_shaders_.rect_list);
CheckResult(err, "vkCreateShaderModule");
shader_module_info.codeSize = static_cast<uint32_t>(sizeof(dummy_frag));
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(dummy_frag);
err = vkCreateShaderModule(device_, &shader_module_info, nullptr,
&dummy_pixel_shader_);
// We can also use the GLSL translator with a Vulkan dialect.
shader_translator_.reset(new SpirvShaderTranslator());
}
PipelineCache::~PipelineCache() {
@@ -127,6 +135,7 @@ PipelineCache::~PipelineCache() {
vkDestroyShaderModule(device_, geometry_shaders_.point_list, nullptr);
vkDestroyShaderModule(device_, geometry_shaders_.quad_list, nullptr);
vkDestroyShaderModule(device_, geometry_shaders_.rect_list, nullptr);
vkDestroyShaderModule(device_, dummy_pixel_shader_, nullptr);
vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
vkDestroyPipelineCache(device_, pipeline_cache_, nullptr);
@@ -261,9 +270,12 @@ VkPipeline PipelineCache::GetPipeline(const RenderState* render_state,
pipeline_info.basePipelineHandle = nullptr;
pipeline_info.basePipelineIndex = -1;
VkPipeline pipeline = nullptr;
auto err = vkCreateGraphicsPipelines(device_, pipeline_cache_, 1,
&pipeline_info, nullptr, &pipeline);
CheckResult(err, "vkCreateGraphicsPipelines");
auto result = vkCreateGraphicsPipelines(device_, pipeline_cache_, 1,
&pipeline_info, nullptr, &pipeline);
if (result != VK_SUCCESS) {
XELOGE("vkCreateGraphicsPipelines failed with code %d", result);
return nullptr;
}
// Dump shader disassembly.
if (FLAGS_vulkan_dump_disasm) {
@@ -280,7 +292,7 @@ bool PipelineCache::TranslateShader(VulkanShader* shader,
xenos::xe_gpu_program_cntl_t cntl) {
// Perform translation.
// If this fails the shader will be marked as invalid and ignored later.
if (!shader_translator_.Translate(shader, cntl)) {
if (!shader_translator_->Translate(shader, cntl)) {
XELOGE("Shader translation failed; marking shader as ignored");
return false;
}
@@ -392,6 +404,7 @@ void PipelineCache::DumpShaderDisasmNV(
disasm_fp.c_str());
}
vkDestroyPipeline(device_, dummy_pipeline, nullptr);
vkDestroyPipelineCache(device_, dummy_pipeline_cache, nullptr);
}
@@ -529,9 +542,6 @@ bool PipelineCache::SetDynamicState(VkCommandBuffer command_buffer,
VkViewport viewport_rect;
std::memset(&viewport_rect, 0, sizeof(VkViewport));
viewport_rect.minDepth = 0;
viewport_rect.maxDepth = 1;
if (vport_xscale_enable) {
float texel_offset_x = 0.0f;
float texel_offset_y = 0.0f;
@@ -549,10 +559,6 @@ bool PipelineCache::SetDynamicState(VkCommandBuffer command_buffer,
viewport_rect.y = vpy + texel_offset_y;
viewport_rect.width = vpw;
viewport_rect.height = vph;
// TODO(benvanik): depth range adjustment?
// float voz = vport_zoffset_enable ? regs.pa_cl_vport_zoffset : 0;
// float vsz = vport_zscale_enable ? regs.pa_cl_vport_zscale : 1;
} else {
float texel_offset_x = 0.0f;
float texel_offset_y = 0.0f;
@@ -569,6 +575,8 @@ bool PipelineCache::SetDynamicState(VkCommandBuffer command_buffer,
float vsz = vport_zscale_enable ? regs.pa_cl_vport_zscale : 1;
viewport_rect.minDepth = voz;
viewport_rect.maxDepth = voz + vsz;
assert_true(viewport_rect.minDepth >= 0 && viewport_rect.minDepth <= 1);
assert_true(viewport_rect.maxDepth >= -1 && viewport_rect.maxDepth <= 1);
vkCmdSetViewport(command_buffer, 0, 1, &viewport_rect);
}
@@ -587,24 +595,25 @@ bool PipelineCache::SetDynamicState(VkCommandBuffer command_buffer,
vkCmdSetBlendConstants(command_buffer, regs.rb_blend_rgba);
}
if (full_update) {
// VK_DYNAMIC_STATE_LINE_WIDTH
vkCmdSetLineWidth(command_buffer, 1.0f);
// VK_DYNAMIC_STATE_DEPTH_BIAS
vkCmdSetDepthBias(command_buffer, 0.0f, 0.0f, 0.0f);
// VK_DYNAMIC_STATE_DEPTH_BOUNDS
vkCmdSetDepthBounds(command_buffer, 0.0f, 1.0f);
// VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK
vkCmdSetStencilCompareMask(command_buffer, VK_STENCIL_FRONT_AND_BACK, 0);
bool stencil_state_dirty = full_update;
stencil_state_dirty |=
SetShadowRegister(&regs.rb_stencilrefmask, XE_GPU_REG_RB_STENCILREFMASK);
if (stencil_state_dirty) {
uint32_t stencil_ref = (regs.rb_stencilrefmask & 0xFF);
uint32_t stencil_read_mask = (regs.rb_stencilrefmask >> 8) & 0xFF;
uint32_t stencil_write_mask = (regs.rb_stencilrefmask >> 16) & 0xFF;
// VK_DYNAMIC_STATE_STENCIL_REFERENCE
vkCmdSetStencilReference(command_buffer, VK_STENCIL_FRONT_AND_BACK, 0);
vkCmdSetStencilReference(command_buffer, VK_STENCIL_FRONT_AND_BACK,
stencil_ref);
// VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK
vkCmdSetStencilCompareMask(command_buffer, VK_STENCIL_FRONT_AND_BACK,
stencil_read_mask);
// VK_DYNAMIC_STATE_STENCIL_WRITE_MASK
vkCmdSetStencilWriteMask(command_buffer, VK_STENCIL_FRONT_AND_BACK, 0);
vkCmdSetStencilWriteMask(command_buffer, VK_STENCIL_FRONT_AND_BACK,
stencil_write_mask);
}
bool push_constants_dirty = full_update || viewport_state_dirty;
@@ -676,6 +685,17 @@ bool PipelineCache::SetDynamicState(VkCommandBuffer command_buffer,
kSpirvPushConstantsSize, &push_constants);
}
if (full_update) {
// VK_DYNAMIC_STATE_LINE_WIDTH
vkCmdSetLineWidth(command_buffer, 1.0f);
// VK_DYNAMIC_STATE_DEPTH_BIAS
vkCmdSetDepthBias(command_buffer, 0.0f, 0.0f, 0.0f);
// VK_DYNAMIC_STATE_DEPTH_BOUNDS
vkCmdSetDepthBounds(command_buffer, 0.0f, 1.0f);
}
return true;
}
@@ -775,7 +795,7 @@ PipelineCache::UpdateStatus PipelineCache::UpdateShaderStages(
return UpdateStatus::kError;
}
if (!pixel_shader->is_translated() &&
if (pixel_shader && !pixel_shader->is_translated() &&
!TranslateShader(pixel_shader, sq_program_cntl)) {
XELOGE("Failed to translate the pixel shader!");
return UpdateStatus::kError;
@@ -822,7 +842,8 @@ PipelineCache::UpdateStatus PipelineCache::UpdateShaderStages(
pixel_pipeline_stage.pNext = nullptr;
pixel_pipeline_stage.flags = 0;
pixel_pipeline_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
pixel_pipeline_stage.module = pixel_shader->shader_module();
pixel_pipeline_stage.module =
pixel_shader ? pixel_shader->shader_module() : dummy_pixel_shader_;
pixel_pipeline_stage.pName = "main";
pixel_pipeline_stage.pSpecializationInfo = nullptr;
@@ -1051,6 +1072,7 @@ PipelineCache::UpdateStatus PipelineCache::UpdateRasterizationState(
bool dirty = false;
dirty |= regs.primitive_type != primitive_type;
dirty |= SetShadowRegister(&regs.pa_cl_clip_cntl, XE_GPU_REG_PA_CL_CLIP_CNTL);
dirty |= SetShadowRegister(&regs.pa_su_sc_mode_cntl,
XE_GPU_REG_PA_SU_SC_MODE_CNTL);
dirty |= SetShadowRegister(&regs.pa_sc_screen_scissor_tl,
@@ -1070,14 +1092,14 @@ PipelineCache::UpdateStatus PipelineCache::UpdateRasterizationState(
state_info.pNext = nullptr;
state_info.flags = 0;
// TODO(benvanik): right setting?
state_info.depthClampEnable = VK_FALSE;
state_info.rasterizerDiscardEnable = VK_FALSE;
// ZCLIP_NEAR_DISABLE
// state_info.depthClampEnable = !(regs.pa_cl_clip_cntl & (1 << 26));
// RASTERIZER_DISABLE
// state_info.rasterizerDiscardEnable = !!(regs.pa_cl_clip_cntl & (1 << 22));
// KILL_PIX_POST_EARLY_Z
if (regs.pa_sc_viz_query & 0x80) {
state_info.rasterizerDiscardEnable = VK_TRUE;
}
// CLIP_DISABLE
state_info.depthClampEnable = !!(regs.pa_cl_clip_cntl & (1 << 16));
state_info.rasterizerDiscardEnable = VK_FALSE;
bool poly_mode = ((regs.pa_su_sc_mode_cntl >> 3) & 0x3) != 0;
if (poly_mode) {
@@ -1213,11 +1235,11 @@ PipelineCache::UpdateStatus PipelineCache::UpdateDepthStencilState() {
/* 0 */ VK_STENCIL_OP_KEEP,
/* 1 */ VK_STENCIL_OP_ZERO,
/* 2 */ VK_STENCIL_OP_REPLACE,
/* 3 */ VK_STENCIL_OP_INCREMENT_AND_WRAP,
/* 4 */ VK_STENCIL_OP_DECREMENT_AND_WRAP,
/* 3 */ VK_STENCIL_OP_INCREMENT_AND_CLAMP,
/* 4 */ VK_STENCIL_OP_DECREMENT_AND_CLAMP,
/* 5 */ VK_STENCIL_OP_INVERT,
/* 6 */ VK_STENCIL_OP_INCREMENT_AND_CLAMP,
/* 7 */ VK_STENCIL_OP_DECREMENT_AND_CLAMP,
/* 6 */ VK_STENCIL_OP_INCREMENT_AND_WRAP,
/* 7 */ VK_STENCIL_OP_DECREMENT_AND_WRAP,
};
// Depth state
@@ -1230,9 +1252,6 @@ PipelineCache::UpdateStatus PipelineCache::UpdateDepthStencilState() {
compare_func_map[(regs.rb_depthcontrol >> 4) & 0x7];
state_info.depthBoundsTestEnable = VK_FALSE;
uint32_t stencil_ref = (regs.rb_stencilrefmask & 0x000000FF);
uint32_t stencil_read_mask = (regs.rb_stencilrefmask & 0x0000FF00) >> 8;
// Stencil state
state_info.front.compareOp =
compare_func_map[(regs.rb_depthcontrol >> 8) & 0x7];