DxcContainerBuilder.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // dxcontainerbuilder.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Implements the Dxil Container Builder //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/Support/WinIncludes.h"
  12. #include "dxc/dxcapi.h"
  13. #include "dxc/DxilContainer/DxilContainer.h"
  14. #include "dxc/DxilContainer/DxcContainerBuilder.h"
  15. #include "dxc/Support/Global.h"
  16. #include "dxc/Support/ErrorCodes.h"
  17. #include "dxc/Support/FileIOHelper.h"
  18. #include "dxc/Support/microcom.h"
  19. #include "dxc/Support/dxcapi.impl.h"
  20. #include <algorithm>
  21. #include "llvm/ADT/SmallVector.h"
  22. // This declaration is used for the locally-linked validator.
  23. HRESULT CreateDxcValidator(_In_ REFIID riid, _Out_ LPVOID *ppv);
  24. template <class TInterface>
  25. HRESULT DxilLibCreateInstance(_In_ REFCLSID rclsid, _In_ TInterface **ppInterface);
  26. using namespace hlsl;
  27. HRESULT STDMETHODCALLTYPE DxcContainerBuilder::Load(_In_ IDxcBlob *pSource) {
  28. DxcThreadMalloc TM(m_pMalloc);
  29. try {
  30. IFTBOOL(m_pContainer == nullptr && pSource != nullptr &&
  31. IsDxilContainerLike(pSource->GetBufferPointer(),
  32. pSource->GetBufferSize()),
  33. E_INVALIDARG);
  34. m_pContainer = pSource;
  35. const DxilContainerHeader *pHeader = (DxilContainerHeader *)pSource->GetBufferPointer();
  36. for (DxilPartIterator it = begin(pHeader), itEnd = end(pHeader); it != itEnd; ++it) {
  37. const DxilPartHeader *pPartHeader = *it;
  38. CComPtr<IDxcBlobEncoding> pBlob;
  39. IFT(DxcCreateBlobWithEncodingFromPinned((const void *)(pPartHeader + 1), pPartHeader->PartSize, CP_UTF8, &pBlob));
  40. PartList::iterator itPartList = std::find_if(m_parts.begin(), m_parts.end(), [&](DxilPart part) {
  41. return part.m_fourCC == pPartHeader->PartFourCC;
  42. });
  43. IFTBOOL(itPartList == m_parts.end(), DXC_E_DUPLICATE_PART);
  44. m_parts.emplace_back(DxilPart(pPartHeader->PartFourCC, pBlob));
  45. }
  46. return S_OK;
  47. }
  48. CATCH_CPP_RETURN_HRESULT();
  49. }
  50. HRESULT STDMETHODCALLTYPE DxcContainerBuilder::AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) {
  51. DxcThreadMalloc TM(m_pMalloc);
  52. try {
  53. IFTBOOL(pSource != nullptr && !IsDxilContainerLike(pSource->GetBufferPointer(),
  54. pSource->GetBufferSize()),
  55. E_INVALIDARG);
  56. // You can only add debug info, debug info name, rootsignature, or private data blob
  57. IFTBOOL(fourCC == DxilFourCC::DFCC_ShaderDebugInfoDXIL ||
  58. fourCC == DxilFourCC::DFCC_ShaderDebugName ||
  59. fourCC == DxilFourCC::DFCC_RootSignature ||
  60. fourCC == DxilFourCC::DFCC_ShaderStatistics ||
  61. fourCC == DxilFourCC::DFCC_PrivateData,
  62. E_INVALIDARG);
  63. PartList::iterator it = std::find_if(m_parts.begin(), m_parts.end(), [&](DxilPart part) {
  64. return part.m_fourCC == fourCC;
  65. });
  66. IFTBOOL(it == m_parts.end(), DXC_E_DUPLICATE_PART);
  67. m_parts.emplace_back(DxilPart(fourCC, pSource));
  68. if (fourCC == DxilFourCC::DFCC_RootSignature) {
  69. m_RequireValidation = true;
  70. }
  71. return S_OK;
  72. }
  73. CATCH_CPP_RETURN_HRESULT();
  74. }
  75. HRESULT STDMETHODCALLTYPE DxcContainerBuilder::RemovePart(_In_ UINT32 fourCC) {
  76. DxcThreadMalloc TM(m_pMalloc);
  77. try {
  78. IFTBOOL(fourCC == DxilFourCC::DFCC_ShaderDebugInfoDXIL ||
  79. fourCC == DxilFourCC::DFCC_ShaderDebugName ||
  80. fourCC == DxilFourCC::DFCC_RootSignature ||
  81. fourCC == DxilFourCC::DFCC_PrivateData ||
  82. fourCC == DxilFourCC::DFCC_ShaderStatistics,
  83. E_INVALIDARG); // You can only remove debug info, debug info name, rootsignature, or private data blob
  84. PartList::iterator it =
  85. std::find_if(m_parts.begin(), m_parts.end(),
  86. [&](DxilPart part) { return part.m_fourCC == fourCC; });
  87. IFTBOOL(it != m_parts.end(), DXC_E_MISSING_PART);
  88. m_parts.erase(it);
  89. return S_OK;
  90. }
  91. CATCH_CPP_RETURN_HRESULT();
  92. }
  93. HRESULT STDMETHODCALLTYPE DxcContainerBuilder::SerializeContainer(_Out_ IDxcOperationResult **ppResult) {
  94. DxcThreadMalloc TM(m_pMalloc);
  95. try {
  96. // Allocate memory for new dxil container.
  97. uint32_t ContainerSize = ComputeContainerSize();
  98. CComPtr<AbstractMemoryStream> pMemoryStream;
  99. CComPtr<IDxcBlob> pResult;
  100. IFT(CreateMemoryStream(m_pMalloc, &pMemoryStream));
  101. IFT(pMemoryStream->QueryInterface(&pResult));
  102. IFT(pMemoryStream->Reserve(ContainerSize))
  103. // Update Dxil Container
  104. IFT(UpdateContainerHeader(pMemoryStream, ContainerSize));
  105. // Update offset Table
  106. IFT(UpdateOffsetTable(pMemoryStream));
  107. // Update Parts
  108. IFT(UpdateParts(pMemoryStream));
  109. CComPtr<IDxcBlobUtf8> pValErrorUtf8;
  110. HRESULT valHR = S_OK;
  111. if (m_RequireValidation) {
  112. CComPtr<IDxcValidator> pValidator;
  113. IFT(CreateDxcValidator(IID_PPV_ARGS(&pValidator)));
  114. CComPtr<IDxcOperationResult> pValidationResult;
  115. IFT(pValidator->Validate(pResult, DxcValidatorFlags_RootSignatureOnly, &pValidationResult));
  116. IFT(pValidationResult->GetStatus(&valHR));
  117. if (FAILED(valHR)) {
  118. CComPtr<IDxcBlobEncoding> pValError;
  119. IFT(pValidationResult->GetErrorBuffer(&pValError));
  120. if (pValError->GetBufferPointer() && pValError->GetBufferSize())
  121. IFT(hlsl::DxcGetBlobAsUtf8(pValError, m_pMalloc, &pValErrorUtf8));
  122. }
  123. }
  124. // Combine existing warnings and errors from validation
  125. CComPtr<IDxcBlobEncoding> pErrorBlob;
  126. CDxcMallocHeapPtr<char> errorHeap(m_pMalloc);
  127. SIZE_T warningLength = m_warning ? strlen(m_warning) : 0;
  128. SIZE_T valErrorLength = pValErrorUtf8 ? pValErrorUtf8->GetStringLength() : 0;
  129. SIZE_T totalErrorLength = warningLength + valErrorLength;
  130. if (totalErrorLength) {
  131. SIZE_T errorSizeInBytes = totalErrorLength + 1;
  132. errorHeap.AllocateBytes(errorSizeInBytes);
  133. if (warningLength)
  134. memcpy(errorHeap.m_pData, m_warning, warningLength);
  135. if (valErrorLength)
  136. memcpy(errorHeap.m_pData + warningLength,
  137. pValErrorUtf8->GetStringPointer(),
  138. valErrorLength);
  139. errorHeap.m_pData[totalErrorLength] = L'\0';
  140. IFT(hlsl::DxcCreateBlobWithEncodingOnMalloc(
  141. errorHeap.m_pData, m_pMalloc, errorSizeInBytes,
  142. DXC_CP_UTF8, &pErrorBlob));
  143. errorHeap.Detach();
  144. }
  145. IFT(DxcResult::Create(valHR, DXC_OUT_OBJECT, {
  146. DxcOutputObject::DataOutput(DXC_OUT_OBJECT, pResult, DxcOutNoName),
  147. DxcOutputObject::DataOutput(DXC_OUT_ERRORS, pErrorBlob, DxcOutNoName)
  148. }, ppResult));
  149. return S_OK;
  150. }
  151. CATCH_CPP_RETURN_HRESULT();
  152. }
  153. UINT32 DxcContainerBuilder::ComputeContainerSize() {
  154. UINT32 partsSize = 0;
  155. for (DxilPart part : m_parts) {
  156. partsSize += part.m_Blob->GetBufferSize();
  157. }
  158. return GetDxilContainerSizeFromParts(m_parts.size(), partsSize);
  159. }
  160. HRESULT DxcContainerBuilder::UpdateContainerHeader(AbstractMemoryStream *pStream, uint32_t containerSize) {
  161. DxilContainerHeader header;
  162. InitDxilContainer(&header, m_parts.size(), containerSize);
  163. ULONG cbWritten;
  164. IFR(pStream->Write(&header, sizeof(DxilContainerHeader), &cbWritten));
  165. if (cbWritten != sizeof(DxilContainerHeader)) {
  166. return E_FAIL;
  167. }
  168. return S_OK;
  169. }
  170. HRESULT DxcContainerBuilder::UpdateOffsetTable(AbstractMemoryStream *pStream) {
  171. UINT32 offset = sizeof(DxilContainerHeader) + GetOffsetTableSize(m_parts.size());
  172. for (size_t i = 0; i < m_parts.size(); ++i) {
  173. ULONG cbWritten;
  174. IFR(pStream->Write(&offset, sizeof(UINT32), &cbWritten));
  175. if (cbWritten != sizeof(UINT32)) { return E_FAIL; }
  176. offset += sizeof(DxilPartHeader) + m_parts[i].m_Blob->GetBufferSize();
  177. }
  178. return S_OK;
  179. }
  180. HRESULT DxcContainerBuilder::UpdateParts(AbstractMemoryStream *pStream) {
  181. for (size_t i = 0; i < m_parts.size(); ++i) {
  182. ULONG cbWritten;
  183. CComPtr<IDxcBlob> pBlob = m_parts[i].m_Blob;
  184. // Write part header
  185. DxilPartHeader partHeader = { m_parts[i].m_fourCC, (uint32_t) pBlob->GetBufferSize() };
  186. IFR(pStream->Write(&partHeader, sizeof(DxilPartHeader), &cbWritten));
  187. if (cbWritten != sizeof(DxilPartHeader)) { return E_FAIL; }
  188. // Write part content
  189. IFR(pStream->Write(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), &cbWritten));
  190. if (cbWritten != pBlob->GetBufferSize()) { return E_FAIL; }
  191. }
  192. return S_OK;
  193. }