/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2020 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_GPU_D3D12_D3D12_COMMAND_PROCESSOR_H_ #define XENIA_GPU_D3D12_D3D12_COMMAND_PROCESSOR_H_ #include #include #include #include #include #include #include "xenia/gpu/command_processor.h" #include "xenia/gpu/d3d12/d3d12_graphics_system.h" #include "xenia/gpu/d3d12/deferred_command_list.h" #include "xenia/gpu/d3d12/pipeline_cache.h" #include "xenia/gpu/d3d12/primitive_converter.h" #include "xenia/gpu/d3d12/render_target_cache.h" #include "xenia/gpu/d3d12/shared_memory.h" #include "xenia/gpu/d3d12/texture_cache.h" #include "xenia/gpu/dxbc_shader_translator.h" #include "xenia/gpu/xenos.h" #include "xenia/kernel/kernel_state.h" #include "xenia/ui/d3d12/d3d12_context.h" #include "xenia/ui/d3d12/d3d12_util.h" #include "xenia/ui/d3d12/pools.h" namespace xe { namespace gpu { namespace d3d12 { class D3D12CommandProcessor : public CommandProcessor { public: explicit D3D12CommandProcessor(D3D12GraphicsSystem* graphics_system, kernel::KernelState* kernel_state); ~D3D12CommandProcessor(); void ClearCaches() override; void InitializeShaderStorage(const std::filesystem::path& storage_root, uint32_t title_id, bool blocking) override; void RequestFrameTrace(const std::filesystem::path& root_path) override; void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) override; void RestoreEdramSnapshot(const void* snapshot) override; // Needed by everything that owns transient objects. ui::d3d12::D3D12Context& GetD3D12Context() const { return static_cast(*context_); } // Returns the deferred drawing command list for the currently open // submission. DeferredCommandList& GetDeferredCommandList() { return *deferred_command_list_; } uint64_t GetCurrentSubmission() const { return submission_current_; } uint64_t GetCompletedSubmission() const { return submission_completed_; } uint64_t GetCurrentFrame() const { return frame_current_; } uint64_t GetCompletedFrame() const { return frame_completed_; } // Gets the current color write mask, taking the pixel shader's write mask // into account. If a shader doesn't write to a render target, it shouldn't be // written to and it shouldn't be even bound - otherwise, in Halo 3, one // render target is being destroyed by a shader not writing anything, and in // Banjo-Tooie, the result of clearing the top tile is being ignored because // there are 4 render targets bound with the same EDRAM base (clearly not // correct usage), but the shader only clears 1, and then EDRAM buffer stores // conflict with each other. uint32_t GetCurrentColorMask(const D3D12Shader* pixel_shader) const; void PushTransitionBarrier( ID3D12Resource* resource, D3D12_RESOURCE_STATES old_state, D3D12_RESOURCE_STATES new_state, UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); void PushAliasingBarrier(ID3D12Resource* old_resource, ID3D12Resource* new_resource); void PushUAVBarrier(ID3D12Resource* resource); void SubmitBarriers(); // Finds or creates root signature for a pipeline. ID3D12RootSignature* GetRootSignature(const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader); ui::d3d12::UploadBufferPool& GetConstantBufferPool() const { return *constant_buffer_pool_; } D3D12_CPU_DESCRIPTOR_HANDLE GetViewBindlessHeapCPUStart() const { assert_true(bindless_resources_used_); return view_bindless_heap_cpu_start_; } D3D12_GPU_DESCRIPTOR_HANDLE GetViewBindlessHeapGPUStart() const { assert_true(bindless_resources_used_); return view_bindless_heap_gpu_start_; } // Returns UINT32_MAX if no free descriptors. uint32_t RequestPersistentViewBindlessDescriptor(); void ReleaseViewBindlessDescriptorImmediately(uint32_t descriptor_index); // Request non-contiguous SRV/UAV descriptors for use only within the next // draw or dispatch command done for internal purposes. May change the current // descriptor heap. bool RequestOneUseSingleViewDescriptors( uint32_t count, ui::d3d12::util::DescriptorCPUGPUHandlePair* handles_out); // These are needed often, so they are always allocated. enum class SystemBindlessView : uint32_t { kNullTexture2DArray, kNullTexture3D, kNullTextureCube, kSharedMemoryRawSRV, kSharedMemoryR32UintSRV, kSharedMemoryR32G32UintSRV, kSharedMemoryR32G32B32A32UintSRV, kSharedMemoryRawUAV, kSharedMemoryR32UintUAV, kSharedMemoryR32G32UintUAV, kSharedMemoryR32G32B32A32UintUAV, kEdramRawSRV, kEdramR32UintSRV, kEdramR32G32UintSRV, kEdramR32G32B32A32UintSRV, kEdramRawUAV, kEdramR32UintUAV, kEdramR32G32B32A32UintUAV, kGammaRampNormalSRV, kGammaRampPWLSRV, kCount, }; ui::d3d12::util::DescriptorCPUGPUHandlePair GetSystemBindlessViewHandlePair( SystemBindlessView view) const; ui::d3d12::util::DescriptorCPUGPUHandlePair GetSharedMemoryUintPow2BindlessSRVHandlePair( uint32_t element_size_bytes_pow2) const; ui::d3d12::util::DescriptorCPUGPUHandlePair GetSharedMemoryUintPow2BindlessUAVHandlePair( uint32_t element_size_bytes_pow2) const; ui::d3d12::util::DescriptorCPUGPUHandlePair GetEdramUintPow2BindlessSRVHandlePair(uint32_t element_size_bytes_pow2) const; // Returns a single temporary GPU-side buffer within a submission for tasks // like texture untiling and resolving. ID3D12Resource* RequestScratchGPUBuffer(uint32_t size, D3D12_RESOURCE_STATES state); // This must be called when done with the scratch buffer, to notify the // command processor about the new state in case the buffer was transitioned // by its user. void ReleaseScratchGPUBuffer(ID3D12Resource* buffer, D3D12_RESOURCE_STATES new_state); // Sets the current SSAA sample positions, needs to be done before setting // render targets or copying to depth render targets. void SetSamplePositions(xenos::MsaaSamples sample_positions); // Returns a pipeline state object with deferred creation by its handle. May // return nullptr if failed to create the pipeline state object. inline ID3D12PipelineState* GetD3D12PipelineStateByHandle( void* handle) const { return pipeline_cache_->GetD3D12PipelineStateByHandle(handle); } // Sets the current pipeline state to a compute one. This is for cache // invalidation primarily. A submission must be open. void SetComputePipelineState(ID3D12PipelineState* pipeline_state); // For the pipeline state cache to call when binding layout UIDs may be // reused. void NotifyShaderBindingsLayoutUIDsInvalidated(); // Returns the text to display in the GPU backend name in the window title. std::string GetWindowTitleText() const; std::unique_ptr Capture(); protected: bool SetupContext() override; void ShutdownContext() override; void WriteRegister(uint32_t index, uint32_t value) override; void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width, uint32_t frontbuffer_height) override; void OnPrimaryBufferEnd() override; Shader* LoadShader(xenos::ShaderType shader_type, uint32_t guest_address, const uint32_t* host_address, uint32_t dword_count) override; bool IssueDraw(xenos::PrimitiveType primitive_type, uint32_t index_count, IndexBufferInfo* index_buffer_info, bool major_mode_explicit) override; bool IssueCopy() override; void InitializeTrace() override; void FinalizeTrace() override; private: static constexpr uint32_t kQueueFrames = 3; enum RootParameter : UINT { // Keep the size of the root signature at each stage 13 dwords or less // (better 12 or less) so it fits in user data on AMD. Descriptor tables are // 1 dword, root descriptors are 2 dwords (however, root descriptors require // less setup on the CPU - balance needs to be maintained). // CBVs are set in both bindful and bindless cases via root descriptors. // - Bindful resources - multiple root signatures depending on extra // parameters. // These are always present. // Very frequently changed, especially for UI draws, and for models drawn in // multiple parts - contains vertex and texture fetch constants. kRootParameter_Bindful_FetchConstants = 0, // +2 dwords = 2 in all. // Quite frequently changed (for one object drawn multiple times, for // instance - may contain projection matrices). kRootParameter_Bindful_FloatConstantsVertex, // +2 = 4 in VS. // Less frequently changed (per-material). kRootParameter_Bindful_FloatConstantsPixel, // +2 = 4 in PS. // May stay the same across many draws. kRootParameter_Bindful_SystemConstants, // +2 = 6 in all. // Pretty rarely used and rarely changed - flow control constants. kRootParameter_Bindful_BoolLoopConstants, // +2 = 8 in all. // Never changed except for when starting a new descriptor heap - shared // memory byte address buffer, and, if ROV is used for EDRAM, EDRAM R32_UINT // UAV. // SRV/UAV descriptor table. kRootParameter_Bindful_SharedMemoryAndEdram, // +1 = 9 in all. kRootParameter_Bindful_Count_Base, // Extra parameter that may or may not exist: // - Pixel textures (+1 = 10 in PS). // - Pixel samplers (+1 = 11 in PS). // - Vertex textures (+1 = 10 in VS). // - Vertex samplers (+1 = 11 in VS). kRootParameter_Bindful_Count_Max = kRootParameter_Bindful_Count_Base + 4, // - Bindless resources - two global root signatures (for non-tessellated // and tessellated drawing), so these are always present. kRootParameter_Bindless_FetchConstants = 0, // +2 = 2 in all. kRootParameter_Bindless_FloatConstantsVertex, // +2 = 4 in VS. kRootParameter_Bindless_FloatConstantsPixel, // +2 = 4 in PS. // Changed per-material, texture and sampler descriptor indices. kRootParameter_Bindless_DescriptorIndicesPixel, // +2 = 6 in PS. kRootParameter_Bindless_DescriptorIndicesVertex, // +2 = 6 in VS. kRootParameter_Bindless_SystemConstants, // +2 = 8 in all. kRootParameter_Bindless_BoolLoopConstants, // +2 = 10 in all. // Unbounded sampler descriptor table - changed in case of overflow. kRootParameter_Bindless_SamplerHeap, // +1 = 11 in all. // Unbounded SRV/UAV descriptor table - never changed. kRootParameter_Bindless_ViewHeap, // +1 = 12 in all. kRootParameter_Bindless_Count, }; struct RootBindfulExtraParameterIndices { uint32_t textures_pixel; uint32_t samplers_pixel; uint32_t textures_vertex; uint32_t samplers_vertex; static constexpr uint32_t kUnavailable = UINT32_MAX; }; // Gets the indices of optional root parameters. Returns the total parameter // count. static uint32_t GetRootBindfulExtraParameterIndices( const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader, RootBindfulExtraParameterIndices& indices_out); // BeginSubmission and EndSubmission may be called at any time. If there's an // open non-frame submission, BeginSubmission(true) will promote it to a // frame. EndSubmission(true) will close the frame no matter whether the // submission has already been closed. // Rechecks submission number and reclaims per-submission resources. Pass 0 as // the submission to await to simply check status. void CheckSubmissionFence(uint64_t await_submission); // If is_guest_command is true, a new full frame - with full cleanup of // resources and, if needed, starting capturing - is opened if pending (as // opposed to simply resuming after mid-frame synchronization). void BeginSubmission(bool is_guest_command); // If is_swap is true, a full frame is closed - with, if needed, cache // clearing and stopping capturing. Returns whether the submission was done // successfully, if it has failed, leaves it open. bool EndSubmission(bool is_swap); // Checks if ending a submission right now would not cause potentially more // delay than it would reduce by making the GPU start working earlier - such // as when there are unfinished graphics pipeline state creation requests that // would need to be fulfilled before actually submitting the command list. bool CanEndSubmissionImmediately() const; void AwaitAllSubmissionsCompletion(); // Need to await submission completion before calling. void ClearCommandAllocatorCache(); // Request descriptors and automatically rebind the descriptor heap on the // draw command list. Refer to DescriptorHeapPool::Request for partial/full // update explanation. Doesn't work when bindless descriptors are used. uint64_t RequestViewBindfulDescriptors( uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out); uint64_t RequestSamplerBindfulDescriptors( uint64_t previous_heap_index, uint32_t count_for_partial_update, uint32_t count_for_full_update, D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out, D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out); void UpdateFixedFunctionState(bool primitive_two_faced); void UpdateSystemConstantValues( bool shared_memory_is_uav, bool primitive_two_faced, uint32_t line_loop_closing_index, xenos::Endian index_endian, uint32_t used_texture_mask, bool early_z, uint32_t color_mask, const RenderTargetCache::PipelineRenderTarget render_targets[4]); bool UpdateBindings(const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader, ID3D12RootSignature* root_signature); // Returns dword count for one element for a memexport format, or 0 if it's // not supported by the D3D12 command processor (if it's smaller that 1 dword, // for instance). // TODO(Triang3l): Check if any game uses memexport with formats smaller than // 32 bits per element. static uint32_t GetSupportedMemExportFormatSize(xenos::ColorFormat format); // Returns a buffer for reading GPU data back to the CPU. Assuming // synchronizing immediately after use. Always in COPY_DEST state. ID3D12Resource* RequestReadbackBuffer(uint32_t size); void WriteGammaRampSRV(bool is_pwl, D3D12_CPU_DESCRIPTOR_HANDLE handle) const; bool cache_clear_requested_ = false; bool submission_open_ = false; // Values of submission_fence_. uint64_t submission_current_ = 1; uint64_t submission_completed_ = 0; HANDLE submission_fence_completion_event_ = nullptr; ID3D12Fence* submission_fence_ = nullptr; bool frame_open_ = false; // Guest frame index, since some transient resources can be reused across // submissions. Values updated in the beginning of a frame. uint64_t frame_current_ = 1; uint64_t frame_completed_ = 0; // Submission indices of frames that have already been submitted. uint64_t closed_frame_submissions_[kQueueFrames] = {}; struct CommandAllocator { ID3D12CommandAllocator* command_allocator; uint64_t last_usage_submission; CommandAllocator* next; }; CommandAllocator* command_allocator_writable_first_ = nullptr; CommandAllocator* command_allocator_writable_last_ = nullptr; CommandAllocator* command_allocator_submitted_first_ = nullptr; CommandAllocator* command_allocator_submitted_last_ = nullptr; ID3D12GraphicsCommandList* command_list_ = nullptr; ID3D12GraphicsCommandList1* command_list_1_ = nullptr; std::unique_ptr deferred_command_list_ = nullptr; // Should bindless textures and samplers be used - many times faster // UpdateBindings than bindful (that becomes a significant bottleneck with // bindful - mainly because of CopyDescriptorsSimple, which takes the majority // of UpdateBindings time, and that's outside the emulator's control even). bool bindless_resources_used_ = false; // Should a rasterizer-ordered UAV of the EDRAM buffer with format conversion // and blending performed in pixel shaders be used instead of host render // targets. bool edram_rov_used_ = false; std::unique_ptr constant_buffer_pool_ = nullptr; static constexpr uint32_t kViewBindfulHeapSize = 32768; static_assert(kViewBindfulHeapSize <= D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1); std::unique_ptr view_bindful_heap_pool_ = nullptr; // Currently bound descriptor heap - updated by RequestViewBindfulDescriptors. ID3D12DescriptorHeap* view_bindful_heap_current_; // Rationale: textures have 4 KB alignment in guest memory, and there can be // 512 MB / 4 KB in total of them at most, and multiply by 3 for different // swizzles, signedness, and multiple host textures for one guest texture, and // transient descriptors. Though in reality there will be a lot fewer of // course, this is just a "safe" value. The limit is 1000000 for resource // binding tier 2. static constexpr uint32_t kViewBindlessHeapSize = 262144; static_assert(kViewBindlessHeapSize <= D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2); ID3D12DescriptorHeap* view_bindless_heap_ = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE view_bindless_heap_cpu_start_; D3D12_GPU_DESCRIPTOR_HANDLE view_bindless_heap_gpu_start_; uint32_t view_bindless_heap_allocated_ = 0; std::vector view_bindless_heap_free_; // , sorted by the submission // number. std::deque> view_bindless_one_use_descriptors_; // Direct3D 12 only allows shader-visible heaps with no more than 2048 // samplers (due to Nvidia addressing). However, there's also possibly a weird // bug in the Nvidia driver (tested on 440.97 and earlier on Windows 10 1803) // that caused the sampler with index 2047 not to work if a heap with 8 or // less samplers also exists - in case of Xenia, it's the immediate drawer's // sampler heap. // FIXME(Triang3l): Investigate the issue with the sampler 2047 on Nvidia. static constexpr uint32_t kSamplerHeapSize = 2000; static_assert(kSamplerHeapSize <= D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE); std::unique_ptr sampler_bindful_heap_pool_ = nullptr; ID3D12DescriptorHeap* sampler_bindful_heap_current_; ID3D12DescriptorHeap* sampler_bindless_heap_current_ = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE sampler_bindless_heap_cpu_start_; D3D12_GPU_DESCRIPTOR_HANDLE sampler_bindless_heap_gpu_start_; // Currently the sampler heap is used only for texture cache samplers, so // individual samplers are never freed, and using a simple linear allocator // inside the current heap without a free list. uint32_t sampler_bindless_heap_allocated_ = 0; // , if total sampler count used so far // exceeds kSamplerHeapSize, and the heap has been switched (this is not a // totally impossible situation considering Direct3D 9 has sampler parameter // state instead of sampler objects, and having one "unimportant" parameter // changed may result in doubling of sampler count). Sorted by the submission // number (so checking if the first can be reused is enough). std::deque> sampler_bindless_heaps_overflowed_; // TextureCache::SamplerParameters::value -> indices within the current // bindless sampler heap. std::unordered_map texture_cache_bindless_sampler_map_; // Root signatures for different descriptor counts. std::unordered_map root_signatures_bindful_; ID3D12RootSignature* root_signature_bindless_vs_ = nullptr; ID3D12RootSignature* root_signature_bindless_ds_ = nullptr; std::unique_ptr shared_memory_ = nullptr; std::unique_ptr pipeline_cache_ = nullptr; std::unique_ptr texture_cache_ = nullptr; std::unique_ptr render_target_cache_ = nullptr; std::unique_ptr primitive_converter_ = nullptr; // Mip 0 contains the normal gamma ramp (256 entries), mip 1 contains the PWL // ramp (128 entries). DXGI_FORMAT_R10G10B10A2_UNORM 1D. ID3D12Resource* gamma_ramp_texture_ = nullptr; D3D12_RESOURCE_STATES gamma_ramp_texture_state_; // Upload buffer for an image that is the same as gamma_ramp_, but with // kQueueFrames array layers. ID3D12Resource* gamma_ramp_upload_ = nullptr; uint8_t* gamma_ramp_upload_mapping_ = nullptr; D3D12_PLACED_SUBRESOURCE_FOOTPRINT gamma_ramp_footprints_[kQueueFrames * 2]; static constexpr uint32_t kSwapTextureWidth = 1280; static constexpr uint32_t kSwapTextureHeight = 720; inline std::pair GetSwapTextureSize() const { if (texture_cache_->IsResolutionScale2X()) { return std::make_pair(kSwapTextureWidth * 2, kSwapTextureHeight * 2); } return std::make_pair(kSwapTextureWidth, kSwapTextureHeight); } ID3D12Resource* swap_texture_ = nullptr; D3D12_PLACED_SUBRESOURCE_FOOTPRINT swap_texture_copy_footprint_; UINT64 swap_texture_copy_size_; ID3D12DescriptorHeap* swap_texture_rtv_descriptor_heap_ = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE swap_texture_rtv_; ID3D12DescriptorHeap* swap_texture_srv_descriptor_heap_ = nullptr; // Unsubmitted barrier batch. std::vector barriers_; // , sorted by the submission number. std::deque> buffers_for_deletion_; static constexpr uint32_t kScratchBufferSizeIncrement = 16 * 1024 * 1024; ID3D12Resource* scratch_buffer_ = nullptr; uint32_t scratch_buffer_size_ = 0; D3D12_RESOURCE_STATES scratch_buffer_state_; bool scratch_buffer_used_ = false; static constexpr uint32_t kReadbackBufferSizeIncrement = 16 * 1024 * 1024; ID3D12Resource* readback_buffer_ = nullptr; uint32_t readback_buffer_size_ = 0; std::atomic pix_capture_requested_ = false; bool pix_capturing_; // The current fixed-function drawing state. D3D12_VIEWPORT ff_viewport_; D3D12_RECT ff_scissor_; float ff_blend_factor_[4]; uint32_t ff_stencil_ref_; bool ff_viewport_update_needed_; bool ff_scissor_update_needed_; bool ff_blend_factor_update_needed_; bool ff_stencil_ref_update_needed_; // Current SSAA sample positions (to be updated by the render target cache). xenos::MsaaSamples current_sample_positions_; // Currently bound pipeline state, either a graphics pipeline state object // from the pipeline state cache (with potentially deferred creation - // current_external_pipeline_state_ is nullptr in this case) or a non-Xenos // graphics or compute pipeline state object (current_cached_pipeline_state_ // is nullptr in this case). void* current_cached_pipeline_state_; ID3D12PipelineState* current_external_pipeline_state_; // Currently bound graphics root signature. ID3D12RootSignature* current_graphics_root_signature_; // Extra parameters which may or may not be present. RootBindfulExtraParameterIndices current_graphics_root_bindful_extras_; // Whether root parameters are up to date - reset if a new signature is bound. uint32_t current_graphics_root_up_to_date_; // System shader constants. DxbcShaderTranslator::SystemConstants system_constants_; // Float constant usage masks of the last draw call. uint64_t current_float_constant_map_vertex_[4]; uint64_t current_float_constant_map_pixel_[4]; // Constant buffer bindings. struct ConstantBufferBinding { D3D12_GPU_VIRTUAL_ADDRESS address; bool up_to_date; }; ConstantBufferBinding cbuffer_binding_system_; ConstantBufferBinding cbuffer_binding_float_vertex_; ConstantBufferBinding cbuffer_binding_float_pixel_; ConstantBufferBinding cbuffer_binding_bool_loop_; ConstantBufferBinding cbuffer_binding_fetch_; ConstantBufferBinding cbuffer_binding_descriptor_indices_vertex_; ConstantBufferBinding cbuffer_binding_descriptor_indices_pixel_; // Pages with the descriptors currently used for handling Xenos draw calls. uint64_t draw_view_bindful_heap_index_; uint64_t draw_sampler_bindful_heap_index_; // Whether the last used texture sampler bindings have been written to the // current view descriptor heap. bool bindful_textures_written_vertex_; bool bindful_textures_written_pixel_; bool bindful_samplers_written_vertex_; bool bindful_samplers_written_pixel_; // Layout UIDs and last texture and sampler bindings written to the current // descriptor heaps (for bindful) or descriptor index constant buffer (for // bindless) with the last used descriptor layout. Valid only when: // - For bindful, when bindful_#_written_#_ is true. // - For bindless, when cbuffer_binding_descriptor_indices_#_.up_to_date is // true. size_t current_texture_layout_uid_vertex_; size_t current_texture_layout_uid_pixel_; size_t current_sampler_layout_uid_vertex_; size_t current_sampler_layout_uid_pixel_; // Size of these should be ignored when checking whether these are up to date, // layout UID should be checked first (they will be different for different // binding counts). std::vector current_texture_srv_keys_vertex_; std::vector current_texture_srv_keys_pixel_; std::vector current_samplers_vertex_; std::vector current_samplers_pixel_; std::vector current_sampler_bindless_indices_vertex_; std::vector current_sampler_bindless_indices_pixel_; // Latest bindful descriptor handles used for handling Xenos draw calls. D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_and_edram_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_textures_vertex_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_textures_pixel_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_samplers_vertex_; D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_samplers_pixel_; // Current primitive topology. D3D_PRIMITIVE_TOPOLOGY primitive_topology_; }; } // namespace d3d12 } // namespace gpu } // namespace xe #endif // XENIA_GPU_D3D12_D3D12_COMMAND_PROCESSOR_H_