// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "GPUDeviceDX12.h" #include "ResourceOwnerDX12.h" #if GRAPHICS_API_DIRECTX12 #define DX12_DEFAULT_UPLOAD_PAGE_SIZE (4 * 1014 * 1024) // 4 MB // Upload buffer generations timeout to dispose #define DX12_UPLOAD_PAGE_GEN_TIMEOUT DX12_BACK_BUFFER_COUNT // Upload buffer pages that are not used for a few frames are disposed #define DX12_UPLOAD_PAGE_NOT_USED_FRAME_TIMEOUT 60 class GPUTextureDX12; /// /// Single page for the upload buffer /// class UploadBufferPageDX12 : public GPUResourceDX12, public ResourceOwnerDX12 { public: /// /// Init /// /// Graphics Device /// Page size UploadBufferPageDX12(GPUDeviceDX12* device, uint64 size); public: /// /// Last generation that has been using that page /// uint64 LastGen; /// /// CPU memory address of the page /// void* CPUAddress; /// /// GPU memory address of the page /// D3D12_GPU_VIRTUAL_ADDRESS GPUAddress; /// /// Page size in bytes /// uint64 Size; public: // [GPUResourceDX12] GPUResourceType GetResourceType() const final override { return GPUResourceType::Buffer; } // [ResourceOwnerDX12] GPUResource* AsGPUResource() const override { return (GPUResource*)this; } protected: // [GPUResourceDX12] void OnReleaseGPU() final override; }; /// /// Upload buffer allocation /// struct DynamicAllocation { /// /// CPU memory address of the allocation start. /// void* CPUAddress; /// /// Allocation offset in bytes (from the start of the heap buffer). /// uint64 Offset; /// /// Allocation size in bytes /// uint64 Size; /// /// GPU virtual memory address of the allocation start. /// D3D12_GPU_VIRTUAL_ADDRESS GPUAddress; /// /// Upload buffer page that owns that allocation /// UploadBufferPageDX12* Page; /// /// Generation number of that allocation (generally allocation is invalid after one or two generations) /// uint64 Generation; /// /// Init /// DynamicAllocation() : CPUAddress(nullptr) , Offset(0) , Size(0) , GPUAddress(0) , Page(nullptr) , Generation(0) { } /// /// Init /// /// CPU memory address /// Offset in byes /// Size in byes /// GPU memory address /// Parent page /// Generation DynamicAllocation(void* address, uint64 offset, uint64 size, D3D12_GPU_VIRTUAL_ADDRESS gpuAddress, UploadBufferPageDX12* page, uint64 generation) : CPUAddress(address) , Offset(offset) , Size(size) , GPUAddress(gpuAddress) , Page(page) , Generation(generation) { } /// /// Returns true if allocation is invalid. /// bool IsInvalid() const { return CPUAddress == nullptr || Size == 0 || Page == nullptr; } }; /// /// Uploading data to GPU buffer utility /// class UploadBufferDX12 { private: GPUDeviceDX12* _device; UploadBufferPageDX12* _currentPage; uint64 _currentOffset; uint64 _currentGeneration; Array> _freePages; Array> _usedPages; public: /// /// Init /// /// Graphics Device UploadBufferDX12(GPUDeviceDX12* device); /// /// Destructor /// ~UploadBufferDX12(); public: /// /// Gets the current generation number. /// FORCE_INLINE uint64 GetCurrentGeneration() const { return _currentGeneration; } public: /// /// Allocates memory for custom data in the buffer. /// /// Size of the data in bytes /// Data alignment in buffer in bytes /// Dynamic location DynamicAllocation Allocate(uint64 size, uint64 align); /// /// Uploads data to the buffer. /// /// GPU context to record upload command to it /// Destination buffer /// Destination buffer offset in bytes. /// Data to allocate /// Size of the data in bytes /// True if cannot upload data, otherwise false. bool UploadBuffer(GPUContextDX12* context, ID3D12Resource* buffer, uint32 bufferOffset, const void* data, uint64 size); /// /// Uploads data to the texture. /// /// GPU context to record upload command to it /// Destination texture /// Data to allocate /// Source data row pitch value to upload. /// Source data slice pitch value to upload. /// Mip map to stream index /// Texture array index /// True if cannot upload data, otherwise false. bool UploadTexture(GPUContextDX12* context, ID3D12Resource* texture, const void* srcData, uint32 srcRowPitch, uint32 srcSlicePitch, int32 mipIndex, int32 arrayIndex); public: /// /// Begins new generation. /// /// The generation ID to begin. void BeginGeneration(uint64 generation); private: UploadBufferPageDX12* requestPage(uint64 size); }; #endif