Duckstation/src/util/d3d12_texture.h
Stenzek e3d9ba4c99 Rewrite host GPU abstraction
- Don't have to repeat the same thing for 4 renderers.
 - Add native Metal renderer.
2023-08-20 21:55:38 +10:00

170 lines
5.9 KiB
C++

// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "d3d12_descriptor_heap_manager.h"
#include "d3d12_stream_buffer.h"
#include "gpu_device.h"
#include "gpu_texture.h"
#include <d3d12.h>
#include <limits>
#include <memory>
namespace D3D12MA {
class Allocation;
}
class D3D12Device;
class D3D12Texture final : public GPUTexture
{
friend D3D12Device;
public:
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
~D3D12Texture() override;
void Destroy(bool defer);
ALWAYS_INLINE const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
ALWAYS_INLINE const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; }
ALWAYS_INLINE const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; }
ALWAYS_INLINE D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; }
ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; }
ALWAYS_INLINE ID3D12Resource* GetResource() const { return m_resource.Get(); }
bool IsValid() const override { return static_cast<bool>(m_resource); }
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
void Unmap() override;
void MakeReadyForSampling() override;
void SetDebugName(const std::string_view& name) override;
void TransitionToState(D3D12_RESOURCE_STATES state);
void CommitClear();
void CommitClear(ID3D12GraphicsCommandList* cmdlist);
static u32 CalculateSubresource(u32 layer, u32 level, u32 num_levels);
u32 CalculateSubresource(u32 layer, u32 level) const;
void TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state);
void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 layer, u32 level,
D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const;
void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 subresource,
D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const;
static void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, ID3D12Resource* resource,
u32 subresource, D3D12_RESOURCE_STATES before_state,
D3D12_RESOURCE_STATES after_state);
// Call when the texture is bound to the pipeline, or read from in a copy.
ALWAYS_INLINE void SetUseFenceValue(u64 counter) { m_use_fence_counter = counter; }
private:
enum class WriteDescriptorType : u8
{
None,
RTV,
DSV
};
D3D12Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
DXGI_FORMAT dxgi_format, ComPtr<ID3D12Resource> resource, ComPtr<D3D12MA::Allocation> allocation,
const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor,
const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype,
D3D12_RESOURCE_STATES resource_state);
ID3D12GraphicsCommandList4* GetCommandBufferForUpdate();
ID3D12Resource* AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 width,
u32 height) const;
void CopyTextureDataForUpload(void* dst, const void* src, u32 width, u32 height, u32 pitch, u32 upload_pitch) const;
void ActuallyCommitClear(ID3D12GraphicsCommandList* cmdlist);
ComPtr<ID3D12Resource> m_resource;
ComPtr<D3D12MA::Allocation> m_allocation;
D3D12DescriptorHandle m_srv_descriptor = {};
D3D12DescriptorHandle m_write_descriptor = {};
D3D12DescriptorHandle m_uav_descriptor = {};
DXGI_FORMAT m_dxgi_format = DXGI_FORMAT_UNKNOWN;
D3D12_RESOURCE_STATES m_resource_state = D3D12_RESOURCE_STATE_COMMON;
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;
// Contains the fence counter when the texture was last used.
// When this matches the current fence counter, the texture was used this command buffer.
u64 m_use_fence_counter = 0;
u16 m_map_x = 0;
u16 m_map_y = 0;
u16 m_map_width = 0;
u16 m_map_height = 0;
u8 m_map_layer = 0;
u8 m_map_level = 0;
};
class D3D12Sampler final : public GPUSampler
{
friend D3D12Device;
public:
~D3D12Sampler() override;
ALWAYS_INLINE const D3D12DescriptorHandle& GetDescriptor() const { return m_descriptor; }
void SetDebugName(const std::string_view& name) override;
private:
D3D12Sampler(D3D12DescriptorHandle descriptor);
D3D12DescriptorHandle m_descriptor;
};
class D3D12Framebuffer final : public GPUFramebuffer
{
friend D3D12Device;
public:
~D3D12Framebuffer() override;
ALWAYS_INLINE const D3D12DescriptorHandle& GetRTV() const { return m_rtv; }
ALWAYS_INLINE const D3D12DescriptorHandle& GetDSV() const { return m_dsv; }
void SetDebugName(const std::string_view& name) override;
private:
D3D12Framebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, D3D12DescriptorHandle rtv,
D3D12DescriptorHandle dsv);
D3D12DescriptorHandle m_rtv;
D3D12DescriptorHandle m_dsv;
};
class D3D12TextureBuffer final : public GPUTextureBuffer
{
friend D3D12Device;
public:
D3D12TextureBuffer(Format format, u32 size_in_elements);
~D3D12TextureBuffer() override;
ALWAYS_INLINE const D3D12DescriptorHandle& GetDescriptor() const { return m_descriptor; }
bool Create(D3D12Device& dev);
void Destroy(bool defer);
// Inherited via GPUTextureBuffer
void* Map(u32 required_elements) override;
void Unmap(u32 used_elements) override;
void SetDebugName(const std::string_view& name) override;
private:
D3D12StreamBuffer m_buffer;
D3D12DescriptorHandle m_descriptor;
};