[D3D12] Rewrite pipeline cache for compact storage of pipeline descriptions

This commit is contained in:
Triang3l 2019-01-01 22:20:50 +03:00
parent 317e5c3ce2
commit 1cea4062c0
3 changed files with 698 additions and 673 deletions

View File

@ -1310,11 +1310,10 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
// Create the pipeline if needed and bind it. // Create the pipeline if needed and bind it.
ID3D12PipelineState* pipeline; ID3D12PipelineState* pipeline;
ID3D12RootSignature* root_signature; ID3D12RootSignature* root_signature;
auto pipeline_status = pipeline_cache_->ConfigurePipeline( if (!pipeline_cache_->ConfigurePipeline(
vertex_shader, pixel_shader, primitive_type_converted, vertex_shader, pixel_shader, primitive_type_converted,
indexed ? index_buffer_info->format : IndexFormat::kInt16, indexed ? index_buffer_info->format : IndexFormat::kInt16,
pipeline_render_targets, &pipeline, &root_signature); pipeline_render_targets, &pipeline, &root_signature)) {
if (pipeline_status == PipelineCache::UpdateStatus::kError) {
return false; return false;
} }
if (current_pipeline_ != pipeline) { if (current_pipeline_ != pipeline) {

File diff suppressed because it is too large Load Diff

View File

@ -13,8 +13,6 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "third_party/xxhash/xxhash.h"
#include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/d3d12/d3d12_shader.h"
#include "xenia/gpu/d3d12/render_target_cache.h" #include "xenia/gpu/d3d12/render_target_cache.h"
#include "xenia/gpu/dxbc_shader_translator.h" #include "xenia/gpu/dxbc_shader_translator.h"
@ -29,12 +27,6 @@ class D3D12CommandProcessor;
class PipelineCache { class PipelineCache {
public: public:
enum class UpdateStatus {
kCompatible,
kMismatch,
kError,
};
PipelineCache(D3D12CommandProcessor* command_processor, PipelineCache(D3D12CommandProcessor* command_processor,
RegisterFile* register_file, bool edram_rov_used); RegisterFile* register_file, bool edram_rov_used);
~PipelineCache(); ~PipelineCache();
@ -49,7 +41,7 @@ class PipelineCache {
D3D12Shader* pixel_shader, D3D12Shader* pixel_shader,
PrimitiveType primitive_type); PrimitiveType primitive_type);
UpdateStatus ConfigurePipeline( bool ConfigurePipeline(
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader, D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
PrimitiveType primitive_type, IndexFormat index_format, PrimitiveType primitive_type, IndexFormat index_format,
const RenderTargetCache::PipelineRenderTarget render_targets[5], const RenderTargetCache::PipelineRenderTarget render_targets[5],
@ -59,31 +51,122 @@ class PipelineCache {
void ClearCache(); void ClearCache();
private: private:
bool SetShadowRegister(uint32_t* dest, uint32_t register_name); enum class PipelineStripCutIndex : uint32_t {
bool SetShadowRegister(float* dest, uint32_t register_name); kNone,
kFFFF,
kFFFFFFFF,
};
enum class PipelineTessellationMode : uint32_t {
kNone,
kDiscrete,
kContinuous,
kAdaptive,
};
enum class PipelinePatchType : uint32_t {
kNone,
kLine,
kTriangle,
kQuad,
};
enum class PipelinePrimitiveTopologyType : uint32_t {
kPoint,
kLine,
kTriangle,
kPatch,
};
enum class PipelineGeometryShader : uint32_t {
kNone,
kPointList,
kRectangleList,
kQuadList,
};
enum class PipelineCullMode : uint32_t {
kNone,
kFront,
kBack,
};
enum class PipelineBlendFactor : uint32_t {
kZero,
kOne,
kSrcColor,
kInvSrcColor,
kSrcAlpha,
kInvSrcAlpha,
kDestColor,
kInvDestColor,
kDestAlpha,
kInvDestAlpha,
kBlendFactor,
kInvBlendFactor,
kSrcAlphaSat,
};
struct PipelineRenderTarget {
uint32_t used : 1; // 1
ColorRenderTargetFormat format : 4; // 5
PipelineBlendFactor src_blend : 4; // 9
PipelineBlendFactor dest_blend : 4; // 13
BlendOp blend_op : 3; // 16
PipelineBlendFactor src_blend_alpha : 4; // 20
PipelineBlendFactor dest_blend_alpha : 4; // 24
BlendOp blend_op_alpha : 3; // 27
uint32_t write_mask : 4; // 31
};
struct PipelineDescription {
ID3D12RootSignature* root_signature;
D3D12Shader* vertex_shader;
D3D12Shader* pixel_shader;
int32_t depth_bias;
float depth_bias_slope_scaled;
PipelineStripCutIndex strip_cut_index : 2; // 2
PipelineTessellationMode tessellation_mode : 2; // 4
PipelinePrimitiveTopologyType primitive_topology_type : 2; // 6
PipelinePatchType patch_type : 2; // 8
PipelineGeometryShader geometry_shader : 2; // 10
uint32_t fill_mode_wireframe : 1; // 11
PipelineCullMode cull_mode : 2; // 13
uint32_t front_counter_clockwise : 1; // 14
uint32_t depth_clip : 1; // 15
uint32_t rov_msaa : 1; // 16
DepthRenderTargetFormat depth_format : 1; // 17
uint32_t depth_func : 3; // 20
uint32_t depth_write : 1; // 21
uint32_t stencil_enable : 1; // 22
uint32_t stencil_read_mask : 8; // 30
uint32_t stencil_write_mask : 8; // 8
uint32_t stencil_front_fail_op : 3; // 11
uint32_t stencil_front_depth_fail_op : 3; // 14
uint32_t stencil_front_pass_op : 3; // 17
uint32_t stencil_front_func : 3; // 20
uint32_t stencil_back_fail_op : 3; // 23
uint32_t stencil_back_depth_fail_op : 3; // 26
uint32_t stencil_back_pass_op : 3; // 29
uint32_t stencil_back_func : 3; // 32
PipelineRenderTarget render_targets[4];
};
bool TranslateShader(D3D12Shader* shader, xenos::xe_gpu_program_cntl_t cntl, bool TranslateShader(D3D12Shader* shader, xenos::xe_gpu_program_cntl_t cntl,
PrimitiveType primitive_type); PrimitiveType primitive_type);
UpdateStatus UpdateState( bool GetCurrentStateDescription(
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader, D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
PrimitiveType primitive_type, IndexFormat index_format, PrimitiveType primitive_type, IndexFormat index_format,
const RenderTargetCache::PipelineRenderTarget render_targets[5]); const RenderTargetCache::PipelineRenderTarget render_targets[5],
PipelineDescription& description_out);
// pRootSignature, VS, PS, DS, HS, GS, PrimitiveTopologyType. ID3D12PipelineState* CreatePipelineState(
UpdateStatus UpdateShaderStages(D3D12Shader* vertex_shader, const PipelineDescription& description);
D3D12Shader* pixel_shader,
PrimitiveType primitive_type);
// BlendState, NumRenderTargets, RTVFormats.
UpdateStatus UpdateBlendStateAndRenderTargets(
D3D12Shader* pixel_shader,
const RenderTargetCache::PipelineRenderTarget render_targets[4]);
// RasterizerState.
UpdateStatus UpdateRasterizerState(PrimitiveType primitive_type);
// DepthStencilState, DSVFormat.
UpdateStatus UpdateDepthStencilState(DXGI_FORMAT format);
// IBStripCutValue.
UpdateStatus UpdateIBStripCutValue(IndexFormat index_format);
D3D12CommandProcessor* command_processor_; D3D12CommandProcessor* command_processor_;
RegisterFile* register_file_; RegisterFile* register_file_;
@ -100,85 +183,17 @@ class PipelineCache {
// Xenos pixel shader provided. // Xenos pixel shader provided.
std::vector<uint8_t> depth_only_pixel_shader_; std::vector<uint8_t> depth_only_pixel_shader_;
// Hash state used to incrementally produce pipeline hashes during update.
// By the time the full update pass has run the hash will represent the
// current state in a way that can uniquely identify the produced
// ID3D12PipelineState.
XXH64_state_t hash_state_;
struct Pipeline { struct Pipeline {
ID3D12PipelineState* state; ID3D12PipelineState* state;
// Root signature taken from the command processor. PipelineDescription description;
ID3D12RootSignature* root_signature;
}; };
// All previously generated pipelines mapped by hash. // All previously generated pipelines mapped by hash.
std::unordered_map<uint64_t, Pipeline*> pipelines_; std::unordered_map<uint64_t, Pipeline*> pipelines_;
Pipeline* GetPipeline(uint64_t hash_key);
// Previously used pipeline. This matches our current state settings // Previously used pipeline. This matches our current state settings
// and allows us to quickly(ish) reuse the pipeline if no registers have // and allows us to quickly(ish) reuse the pipeline if no registers have
// changed. // changed.
Pipeline* current_pipeline_ = nullptr; Pipeline* current_pipeline_ = nullptr;
// Description of the pipeline being created.
D3D12_GRAPHICS_PIPELINE_STATE_DESC update_desc_;
struct UpdateShaderStagesRegisters {
D3D12Shader* vertex_shader;
D3D12Shader* pixel_shader;
D3D12_PRIMITIVE_TOPOLOGY_TYPE primitive_topology_type;
// Primitive type if it needs hull/domain shaders or a geometry shader, or
// kNone if should be transformed with only a vertex shader.
PrimitiveType hs_gs_ds_primitive_type;
// Tessellation mode - ignored when not using tessellation (when
// hs_gs_ds_primitive_type is not a patch).
TessellationMode tessellation_mode;
UpdateShaderStagesRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_shader_stages_regs_;
struct UpdateBlendStateAndRenderTargetsRegisters {
RenderTargetCache::PipelineRenderTarget render_targets[5];
// RB_COLOR_MASK with unused render targets removed.
uint32_t color_mask;
// Blend control updated only for used render targets.
uint32_t blendcontrol[4];
bool colorcontrol_blend_enable;
UpdateBlendStateAndRenderTargetsRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_blend_state_and_render_targets_regs_;
struct UpdateRasterizerStateRegisters {
// The constant factor of the polygon offset is multiplied by a value that
// depends on the depth buffer format here.
float poly_offset;
float poly_offset_scale;
uint8_t cull_mode;
bool fill_mode_wireframe;
bool front_counter_clockwise;
bool depth_clamp_enable;
bool msaa_rov;
UpdateRasterizerStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_rasterizer_state_regs_;
struct UpdateDepthStencilStateRegisters {
DXGI_FORMAT format;
uint32_t rb_depthcontrol;
uint32_t rb_stencilrefmask;
UpdateDepthStencilStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_depth_stencil_state_regs_;
struct UpdateIBStripCutValueRegisters {
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE ib_strip_cut_value;
UpdateIBStripCutValueRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_ib_strip_cut_value_regs_;
}; };
} // namespace d3d12 } // namespace d3d12