29void DownsampleRGBA8(
const uint8_t* src, uint32_t
width, uint32_t
height,
30 std::vector<uint8_t>& dst) {
31 const uint32_t dstWidth = (std::max)(1u,
width / 2);
32 const uint32_t dstHeight = (std::max)(1u,
height / 2);
33 dst.resize(
static_cast<size_t>(dstWidth) * dstHeight * 4);
35 for (uint32_t y = 0; y < dstHeight; ++y) {
36 const uint32_t y0 = (std::min)(y * 2,
height - 1);
37 const uint32_t y1 = (std::min)(y * 2 + 1,
height - 1);
38 for (uint32_t x = 0; x < dstWidth; ++x) {
39 const uint32_t x0 = (std::min)(x * 2,
width - 1);
40 const uint32_t x1 = (std::min)(x * 2 + 1,
width - 1);
41 for (uint32_t c = 0; c < 4; ++c) {
42 const uint32_t sum = src[(y0 *
width + x0) * 4 + c] +
43 src[(y0 *
width + x1) * 4 + c] +
44 src[(y1 *
width + x0) * 4 + c] +
45 src[(y1 *
width + x1) * 4 + c];
46 dst[(
static_cast<size_t>(y) * dstWidth + x) * 4 + c] =
47 static_cast<uint8_t
>((sum + 2) / 4);
54DirectX12Texture::DirectX12Texture(ID3D12Device* device,
55 ID3D12CommandQueue* commandQueue,
56 ID3D12GraphicsCommandList* commandList,
59 m_commandQueue(commandQueue),
60 m_commandList(commandList),
61 m_uploader(uploader) {}
63DirectX12Texture::~DirectX12Texture() {
64 DirectX12Buffer::DeferCleanup(std::move(m_srvHeap));
65 DirectX12Buffer::DeferCleanup(std::move(m_texture));
68bool DirectX12Texture::LoadFromMemory(
const void* data, uint32_t
width,
70 TextureFormat format) {
71 if (!data || !m_device ||
width == 0 ||
height == 0)
return false;
78 DXGI_FORMAT dxgiFormat = GetDXGIFormat(format);
80 if (!CreateTextureResource(
width,
height, dxgiFormat))
return false;
81 if (!UploadTextureData(data,
width,
height))
return false;
82 if (!CreateSRV(dxgiFormat))
return false;
87bool DirectX12Texture::LoadFromFile(
const std::string& filePath) {
89 unsigned char* pixels =
90 stbi_load(filePath.c_str(), &w, &h, &channels, 4);
92 SLEAK_ERROR(
"DirectX12Texture: Failed to load image: {}",
97 bool result = LoadFromMemory(pixels,
static_cast<uint32_t
>(w),
98 static_cast<uint32_t
>(h),
99 TextureFormat::RGBA8);
100 stbi_image_free(pixels);
104void DirectX12Texture::Bind(uint32_t slot)
const {
105 if (m_commandList && m_srvHeap) {
106 BindToCommandList(m_commandList, 2);
110void DirectX12Texture::Unbind()
const {
114void DirectX12Texture::SetFilter(TextureFilter filter) {
120void DirectX12Texture::SetWrapMode(TextureWrapMode wrapMode) {
121 m_wrapMode = wrapMode;
124void DirectX12Texture::BindToCommandList(
125 ID3D12GraphicsCommandList* cmdList, UINT rootParameterIndex)
const {
126 if (!cmdList)
return;
128 if (m_usesSharedHeap) {
130 cmdList->SetGraphicsRootDescriptorTable(rootParameterIndex, m_srvGpuHandle);
131 }
else if (m_srvHeap) {
133 ID3D12DescriptorHeap* heaps[] = {m_srvHeap.Get()};
134 cmdList->SetDescriptorHeaps(1, heaps);
135 cmdList->SetGraphicsRootDescriptorTable(
137 m_srvHeap->GetGPUDescriptorHandleForHeapStart());
141bool DirectX12Texture::CreateTextureResource(uint32_t
width,
143 DXGI_FORMAT format) {
144 D3D12_RESOURCE_DESC texDesc{};
145 texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
146 texDesc.Alignment = 0;
147 texDesc.Width =
width;
149 texDesc.DepthOrArraySize = 1;
150 texDesc.MipLevels =
static_cast<UINT16
>(m_mipLevels);
151 texDesc.Format = format;
152 texDesc.SampleDesc.Count = 1;
153 texDesc.SampleDesc.Quality = 0;
154 texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
155 texDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
157 D3D12_HEAP_PROPERTIES heapProps{};
158 heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
159 heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
160 heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
161 heapProps.CreationNodeMask = 1;
162 heapProps.VisibleNodeMask = 1;
164 HRESULT hr = m_device->CreateCommittedResource(
165 &heapProps, D3D12_HEAP_FLAG_NONE, &texDesc,
166 D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
167 IID_PPV_ARGS(&m_texture));
171 "DirectX12Texture: Failed to create texture resource "
173 static_cast<unsigned int>(hr));
180bool DirectX12Texture::UploadTextureData(
const void* data,
183 const UINT mipCount = m_mipLevels;
184 std::vector<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> footprints(mipCount);
185 std::vector<UINT> numRows(mipCount);
186 std::vector<UINT64> rowSizes(mipCount);
187 UINT64 totalBytes = 0;
188 D3D12_RESOURCE_DESC texDesc = m_texture->GetDesc();
189 m_device->GetCopyableFootprints(&texDesc, 0, mipCount, 0, footprints.data(),
190 numRows.data(), rowSizes.data(),
193 DirectX12UploadContext local;
194 DirectX12UploadContext* uploader = m_uploader;
196 if (!local.Initialize(m_device, m_commandQueue))
return false;
200 ID3D12Resource* staging =
nullptr;
202 static_cast<BYTE*
>(uploader->AllocateStaging(totalBytes, &staging));
204 SLEAK_ERROR(
"DirectX12Texture: Failed to allocate staging memory");
208 const uint8_t* level =
static_cast<const uint8_t*
>(data);
209 std::vector<uint8_t> current;
210 std::vector<uint8_t> next;
211 uint32_t levelWidth =
width;
212 uint32_t levelHeight =
height;
214 for (UINT mip = 0; mip < mipCount; ++mip) {
215 const UINT rowBytes = levelWidth * 4;
216 BYTE* destRow = mapped + footprints[mip].Offset;
217 for (UINT row = 0; row < numRows[mip]; ++row) {
218 memcpy(destRow + row * footprints[mip].Footprint.RowPitch,
219 level + row * rowBytes, rowBytes);
222 if (mip + 1 < mipCount) {
223 DownsampleRGBA8(level, levelWidth, levelHeight, next);
225 level = current.data();
226 levelWidth = (std::max)(1u, levelWidth / 2);
227 levelHeight = (std::max)(1u, levelHeight / 2);
231 ID3D12GraphicsCommandList* cmdList = uploader->GetCommandList();
232 for (UINT mip = 0; mip < mipCount; ++mip) {
233 D3D12_TEXTURE_COPY_LOCATION dst{};
234 dst.pResource = m_texture.Get();
235 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
236 dst.SubresourceIndex = mip;
238 D3D12_TEXTURE_COPY_LOCATION src{};
239 src.pResource = staging;
240 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
241 src.PlacedFootprint = footprints[mip];
243 cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src,
nullptr);
247 D3D12_RESOURCE_BARRIER barrier{};
248 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
249 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
250 barrier.Transition.pResource = m_texture.Get();
251 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
252 barrier.Transition.StateAfter =
253 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
254 barrier.Transition.Subresource =
255 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
256 cmdList->ResourceBarrier(1, &barrier);
258 if (uploader == &local) local.Flush();
262bool DirectX12Texture::CreateSRV(DXGI_FORMAT format) {
264 D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc{};
265 srvHeapDesc.NumDescriptors = 1;
266 srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
267 srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
269 HRESULT hr = m_device->CreateDescriptorHeap(
270 &srvHeapDesc, IID_PPV_ARGS(&m_srvHeap));
273 "DirectX12Texture: Failed to create SRV descriptor heap");
278 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};
279 srvDesc.Shader4ComponentMapping =
280 D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
281 srvDesc.Format = format;
282 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
283 srvDesc.Texture2D.MipLevels = m_mipLevels;
285 m_device->CreateShaderResourceView(
286 m_texture.Get(), &srvDesc,
287 m_srvHeap->GetCPUDescriptorHandleForHeapStart());
292bool DirectX12Texture::CreateSRVIntoHandle(DXGI_FORMAT format,
293 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle) {
294 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};
295 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
296 srvDesc.Format = format;
297 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
298 srvDesc.Texture2D.MipLevels = m_mipLevels;
299 m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, cpuHandle);
303DXGI_FORMAT DirectX12Texture::GetDXGIFormat(TextureFormat format)
const {
305 case TextureFormat::RGBA8:
306 return DXGI_FORMAT_R8G8B8A8_UNORM;
307 case TextureFormat::BGRA8:
308 return DXGI_FORMAT_B8G8R8A8_UNORM;
309 case TextureFormat::RGB8:
310 return DXGI_FORMAT_R8G8B8A8_UNORM;
312 return DXGI_FORMAT_R8G8B8A8_UNORM;
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.