2
0

ComputeBufferDX12.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2025 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #ifdef JPH_USE_DX12
  6. #include <Jolt/Compute/DX12/ComputeBufferDX12.h>
  7. #include <Jolt/Compute/DX12/ComputeSystemDX12.h>
  8. JPH_NAMESPACE_BEGIN
  9. ComputeBufferDX12::ComputeBufferDX12(ComputeSystemDX12 *inComputeSystem, EType inType, uint64 inSize, uint inStride) :
  10. ComputeBuffer(inType, inSize, inStride),
  11. mComputeSystem(inComputeSystem)
  12. {
  13. }
  14. bool ComputeBufferDX12::Initialize(const void *inData)
  15. {
  16. uint64 buffer_size = mSize * mStride;
  17. switch (mType)
  18. {
  19. case EType::UploadBuffer:
  20. mBufferCPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  21. mBufferGPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  22. if (mBufferCPU == nullptr || mBufferGPU == nullptr)
  23. return false;
  24. break;
  25. case EType::ConstantBuffer:
  26. mBufferCPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  27. if (mBufferCPU == nullptr)
  28. return false;
  29. break;
  30. case EType::ReadbackBuffer:
  31. JPH_ASSERT(inData == nullptr, "Can't upload data to a readback buffer");
  32. mBufferCPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  33. if (mBufferCPU == nullptr)
  34. return false;
  35. break;
  36. case EType::Buffer:
  37. JPH_ASSERT(inData != nullptr);
  38. mBufferCPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  39. mBufferGPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  40. if (mBufferCPU == nullptr || mBufferGPU == nullptr)
  41. return false;
  42. mNeedsSync = true;
  43. break;
  44. case EType::RWBuffer:
  45. if (inData != nullptr)
  46. {
  47. mBufferCPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_FLAG_NONE, buffer_size);
  48. if (mBufferCPU == nullptr)
  49. return false;
  50. mNeedsSync = true;
  51. }
  52. mBufferGPU = mComputeSystem->CreateD3DResource(D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, buffer_size);
  53. if (mBufferGPU == nullptr)
  54. return false;
  55. break;
  56. }
  57. // Copy data to upload buffer
  58. if (inData != nullptr)
  59. {
  60. void *data = nullptr;
  61. D3D12_RANGE range = { 0, 0 }; // We're not going to read
  62. mBufferCPU->Map(0, &range, &data);
  63. memcpy(data, inData, size_t(buffer_size));
  64. mBufferCPU->Unmap(0, nullptr);
  65. }
  66. return true;
  67. }
  68. bool ComputeBufferDX12::Barrier(ID3D12GraphicsCommandList *inCommandList, D3D12_RESOURCE_STATES inTo) const
  69. {
  70. // Check if state changed
  71. if (mCurrentState == inTo)
  72. return false;
  73. // Only buffers in GPU memory can change state
  74. if (mType != ComputeBuffer::EType::Buffer && mType != ComputeBuffer::EType::RWBuffer)
  75. return true;
  76. D3D12_RESOURCE_BARRIER barrier;
  77. barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  78. barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  79. barrier.Transition.pResource = GetResourceGPU();
  80. barrier.Transition.StateBefore = mCurrentState;
  81. barrier.Transition.StateAfter = inTo;
  82. barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
  83. inCommandList->ResourceBarrier(1, &barrier);
  84. mCurrentState = inTo;
  85. return true;
  86. }
  87. void ComputeBufferDX12::RWBarrier(ID3D12GraphicsCommandList *inCommandList)
  88. {
  89. JPH_ASSERT(mCurrentState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
  90. D3D12_RESOURCE_BARRIER barrier;
  91. barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
  92. barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  93. barrier.Transition.pResource = GetResourceGPU();
  94. inCommandList->ResourceBarrier(1, &barrier);
  95. }
  96. bool ComputeBufferDX12::SyncCPUToGPU(ID3D12GraphicsCommandList *inCommandList) const
  97. {
  98. if (!mNeedsSync)
  99. return false;
  100. Barrier(inCommandList, D3D12_RESOURCE_STATE_COPY_DEST);
  101. inCommandList->CopyResource(GetResourceGPU(), GetResourceCPU());
  102. mNeedsSync = false;
  103. return true;
  104. }
  105. void *ComputeBufferDX12::MapInternal(EMode inMode)
  106. {
  107. void *mapped_resource = nullptr;
  108. switch (inMode)
  109. {
  110. case EMode::Read:
  111. JPH_ASSERT(mType == EType::ReadbackBuffer);
  112. if (HRFailed(mBufferCPU->Map(0, nullptr, &mapped_resource)))
  113. return nullptr;
  114. break;
  115. case EMode::Write:
  116. {
  117. JPH_ASSERT(mType == EType::UploadBuffer || mType == EType::ConstantBuffer);
  118. D3D12_RANGE range = { 0, 0 }; // We're not going to read
  119. if (HRFailed(mBufferCPU->Map(0, &range, &mapped_resource)))
  120. return nullptr;
  121. mNeedsSync = true;
  122. }
  123. break;
  124. }
  125. return mapped_resource;
  126. }
  127. void ComputeBufferDX12::UnmapInternal()
  128. {
  129. mBufferCPU->Unmap(0, nullptr);
  130. }
  131. ComputeBufferResult ComputeBufferDX12::CreateReadBackBuffer() const
  132. {
  133. return mComputeSystem->CreateComputeBuffer(EType::ReadbackBuffer, mSize, mStride);
  134. }
  135. JPH_NAMESPACE_END
  136. #endif // JPH_USE_DX12