duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

d3d11_texture.cpp (18636B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #include "d3d11_texture.h"
      5 #include "d3d11_device.h"
      6 #include "d3d_common.h"
      7 
      8 #include "common/assert.h"
      9 #include "common/log.h"
     10 #include "common/string_util.h"
     11 
     12 #include "fmt/format.h"
     13 
     14 #include <array>
     15 
     16 Log_SetChannel(D3D11Device);
     17 
     18 std::unique_ptr<GPUTexture> D3D11Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
     19                                                        GPUTexture::Type type, GPUTexture::Format format,
     20                                                        const void* data, u32 data_stride)
     21 {
     22   return D3D11Texture::Create(m_device.Get(), width, height, layers, levels, samples, type, format, data, data_stride);
     23 }
     24 
     25 bool D3D11Device::SupportsTextureFormat(GPUTexture::Format format) const
     26 {
     27   const DXGI_FORMAT dfmt = D3DCommon::GetFormatMapping(format).resource_format;
     28   if (dfmt == DXGI_FORMAT_UNKNOWN)
     29     return false;
     30 
     31   UINT support = 0;
     32   const UINT required = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE;
     33   return (SUCCEEDED(m_device->CheckFormatSupport(dfmt, &support)) && ((support & required) == required));
     34 }
     35 
     36 D3D11Sampler::D3D11Sampler(ComPtr<ID3D11SamplerState> ss) : m_ss(std::move(ss))
     37 {
     38 }
     39 
     40 D3D11Sampler::~D3D11Sampler() = default;
     41 
     42 void D3D11Sampler::SetDebugName(std::string_view name)
     43 {
     44   SetD3DDebugObjectName(m_ss.Get(), name);
     45 }
     46 
     47 std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config& config)
     48 {
     49   static constexpr std::array<D3D11_TEXTURE_ADDRESS_MODE, static_cast<u8>(GPUSampler::AddressMode::MaxCount)> ta = {{
     50     D3D11_TEXTURE_ADDRESS_WRAP,   // Repeat
     51     D3D11_TEXTURE_ADDRESS_CLAMP,  // ClampToEdge
     52     D3D11_TEXTURE_ADDRESS_BORDER, // ClampToBorder
     53     D3D11_TEXTURE_ADDRESS_MIRROR, // MirrorRepeat
     54   }};
     55   static constexpr u8 filter_count = static_cast<u8>(GPUSampler::Filter::MaxCount);
     56   static constexpr D3D11_FILTER filters[filter_count][filter_count][filter_count] = {
     57     {
     58       {D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT},
     59       {D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT},
     60     },
     61     {
     62       {D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR, D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR},
     63       {D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, D3D11_FILTER_MIN_MAG_MIP_LINEAR},
     64     }};
     65 
     66   D3D11_SAMPLER_DESC desc = {};
     67   desc.AddressU = ta[static_cast<u8>(config.address_u.GetValue())];
     68   desc.AddressV = ta[static_cast<u8>(config.address_v.GetValue())];
     69   desc.AddressW = ta[static_cast<u8>(config.address_w.GetValue())];
     70   std::memcpy(desc.BorderColor, RGBA8ToFloat(config.border_color).data(), sizeof(desc.BorderColor));
     71   desc.MinLOD = static_cast<float>(config.min_lod);
     72   desc.MaxLOD = static_cast<float>(config.max_lod);
     73 
     74   if (config.anisotropy > 1)
     75   {
     76     desc.Filter = D3D11_FILTER_ANISOTROPIC;
     77     desc.MaxAnisotropy = config.anisotropy;
     78   }
     79   else
     80   {
     81     desc.Filter = filters[static_cast<u8>(config.mip_filter.GetValue())][static_cast<u8>(config.min_filter.GetValue())]
     82                          [static_cast<u8>(config.mag_filter.GetValue())];
     83     desc.MaxAnisotropy = 1;
     84   }
     85 
     86   ComPtr<ID3D11SamplerState> ss;
     87   const HRESULT hr = m_device->CreateSamplerState(&desc, ss.GetAddressOf());
     88   if (FAILED(hr)) [[unlikely]]
     89   {
     90     ERROR_LOG("CreateSamplerState() failed: {:08X}", static_cast<unsigned>(hr));
     91     return {};
     92   }
     93 
     94   return std::unique_ptr<GPUSampler>(new D3D11Sampler(std::move(ss)));
     95 }
     96 
     97 D3D11Texture::D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
     98                            ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
     99                            ComPtr<ID3D11View> rtv_dsv, ComPtr<ID3D11UnorderedAccessView> uav)
    100   : GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
    101                static_cast<u8>(samples), type, format),
    102     m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv_dsv(std::move(rtv_dsv)), m_uav(std::move(uav))
    103 {
    104 }
    105 
    106 D3D11Texture::~D3D11Texture()
    107 {
    108   D3D11Device::GetInstance().UnbindTexture(this);
    109 }
    110 
    111 D3D11_TEXTURE2D_DESC D3D11Texture::GetDesc() const
    112 {
    113   D3D11_TEXTURE2D_DESC desc;
    114   m_texture->GetDesc(&desc);
    115   return desc;
    116 }
    117 
    118 void D3D11Texture::CommitClear(ID3D11DeviceContext1* context)
    119 {
    120   if (m_state == GPUTexture::State::Dirty)
    121     return;
    122 
    123   if (IsDepthStencil())
    124   {
    125     if (m_state == GPUTexture::State::Invalidated)
    126       context->DiscardView(GetD3DDSV());
    127     else
    128       context->ClearDepthStencilView(GetD3DDSV(), D3D11_CLEAR_DEPTH, GetClearDepth(), 0);
    129   }
    130   else if (IsRenderTarget() || IsRWTexture())
    131   {
    132     if (m_state == GPUTexture::State::Invalidated)
    133       context->DiscardView(GetD3DRTV());
    134     else
    135       context->ClearRenderTargetView(GetD3DRTV(), GetUNormClearColor().data());
    136   }
    137 
    138   m_state = GPUTexture::State::Dirty;
    139 }
    140 
    141 bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
    142                           u32 level /*= 0*/)
    143 {
    144   if (m_type == Type::DynamicTexture)
    145   {
    146     void* map;
    147     u32 map_stride;
    148     if (!Map(&map, &map_stride, x, y, width, height, layer, level))
    149       return false;
    150 
    151     StringUtil::StrideMemCpy(map, map_stride, data, pitch, GetPixelSize() * width, height);
    152     Unmap();
    153     return true;
    154   }
    155 
    156   const CD3D11_BOX box(static_cast<LONG>(x), static_cast<LONG>(y), 0, static_cast<LONG>(x + width),
    157                        static_cast<LONG>(y + height), 1);
    158   const u32 srnum = D3D11CalcSubresource(level, layer, m_levels);
    159 
    160   ID3D11DeviceContext1* context = D3D11Device::GetD3DContext();
    161   CommitClear(context);
    162 
    163   GPUDevice::GetStatistics().buffer_streamed += height * pitch;
    164   GPUDevice::GetStatistics().num_uploads++;
    165 
    166   context->UpdateSubresource(m_texture.Get(), srnum, &box, data, pitch, 0);
    167   m_state = GPUTexture::State::Dirty;
    168   return true;
    169 }
    170 
    171 bool D3D11Texture::Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer /*= 0*/,
    172                        u32 level /*= 0*/)
    173 {
    174   if (m_type != Type::DynamicTexture || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) ||
    175       layer > m_layers || level > m_levels)
    176   {
    177     return false;
    178   }
    179 
    180   const bool discard = (width == m_width && height == m_height);
    181   const u32 srnum = D3D11CalcSubresource(level, layer, m_levels);
    182 
    183   ID3D11DeviceContext1* context = D3D11Device::GetD3DContext();
    184   CommitClear(context);
    185 
    186   D3D11_MAPPED_SUBRESOURCE sr;
    187   HRESULT hr = context->Map(m_texture.Get(), srnum, discard ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_READ_WRITE, 0, &sr);
    188   if (FAILED(hr)) [[unlikely]]
    189   {
    190     ERROR_LOG("Map pixels texture failed: {:08X}", static_cast<unsigned>(hr));
    191     return false;
    192   }
    193 
    194   GPUDevice::GetStatistics().buffer_streamed += height * sr.RowPitch;
    195   GPUDevice::GetStatistics().num_uploads++;
    196 
    197   *map = static_cast<u8*>(sr.pData) + (y * sr.RowPitch) + (x * GetPixelSize());
    198   *map_stride = sr.RowPitch;
    199   m_mapped_subresource = srnum;
    200   m_state = GPUTexture::State::Dirty;
    201   return true;
    202 }
    203 
    204 void D3D11Texture::Unmap()
    205 {
    206   D3D11Device::GetD3DContext()->Unmap(m_texture.Get(), m_mapped_subresource);
    207   m_mapped_subresource = 0;
    208 }
    209 
    210 void D3D11Texture::SetDebugName(std::string_view name)
    211 {
    212   SetD3DDebugObjectName(m_texture.Get(), name);
    213 }
    214 
    215 DXGI_FORMAT D3D11Texture::GetDXGIFormat() const
    216 {
    217   return D3DCommon::GetFormatMapping(m_format).resource_format;
    218 }
    219 
    220 std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels,
    221                                                    u32 samples, Type type, Format format,
    222                                                    const void* initial_data /* = nullptr */,
    223                                                    u32 initial_data_stride /* = 0 */)
    224 {
    225   if (!ValidateConfig(width, height, layers, layers, samples, type, format))
    226     return nullptr;
    227 
    228   u32 bind_flags = 0;
    229   D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
    230   u32 cpu_access = 0;
    231   switch (type)
    232   {
    233     case Type::RenderTarget:
    234       bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    235       break;
    236     case Type::DepthStencil:
    237       bind_flags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    238       break;
    239     case Type::Texture:
    240       bind_flags = D3D11_BIND_SHADER_RESOURCE;
    241       break;
    242     case Type::DynamicTexture:
    243       bind_flags = D3D11_BIND_SHADER_RESOURCE;
    244       usage = D3D11_USAGE_DYNAMIC;
    245       cpu_access = D3D11_CPU_ACCESS_WRITE;
    246       break;
    247     case Type::RWTexture:
    248       bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
    249       break;
    250     default:
    251       break;
    252   }
    253 
    254   const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
    255 
    256   CD3D11_TEXTURE2D_DESC desc(fm.resource_format, width, height, layers, levels, bind_flags, usage, cpu_access, samples,
    257                              0, 0);
    258 
    259   D3D11_SUBRESOURCE_DATA srd;
    260   srd.pSysMem = initial_data;
    261   srd.SysMemPitch = initial_data_stride;
    262   srd.SysMemSlicePitch = initial_data_stride * height;
    263 
    264   ComPtr<ID3D11Texture2D> texture;
    265   const HRESULT tex_hr = device->CreateTexture2D(&desc, initial_data ? &srd : nullptr, texture.GetAddressOf());
    266   if (FAILED(tex_hr))
    267   {
    268     ERROR_LOG("Create texture failed: 0x{:08X} ({}x{} levels:{} samples:{} format:{} bind_flags:{:X} initial_data:{})",
    269               static_cast<unsigned>(tex_hr), width, height, levels, samples, static_cast<unsigned>(format), bind_flags,
    270               initial_data);
    271     return nullptr;
    272   }
    273 
    274   if (initial_data)
    275   {
    276     GPUDevice::GetStatistics().buffer_streamed += height * initial_data_stride;
    277     GPUDevice::GetStatistics().num_uploads++;
    278   }
    279 
    280   ComPtr<ID3D11ShaderResourceView> srv;
    281   if (bind_flags & D3D11_BIND_SHADER_RESOURCE)
    282   {
    283     const D3D11_SRV_DIMENSION srv_dimension =
    284       (desc.SampleDesc.Count > 1) ?
    285         D3D11_SRV_DIMENSION_TEXTURE2DMS :
    286         (desc.ArraySize > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DARRAY : D3D11_SRV_DIMENSION_TEXTURE2D);
    287     const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(srv_dimension, fm.srv_format, 0, desc.MipLevels, 0, desc.ArraySize);
    288     const HRESULT hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf());
    289     if (FAILED(hr)) [[unlikely]]
    290     {
    291       ERROR_LOG("Create SRV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
    292       return nullptr;
    293     }
    294   }
    295 
    296   ComPtr<ID3D11View> rtv_dsv;
    297   if (bind_flags & D3D11_BIND_RENDER_TARGET)
    298   {
    299     const D3D11_RTV_DIMENSION rtv_dimension =
    300       (desc.SampleDesc.Count > 1) ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
    301     const CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(rtv_dimension, fm.rtv_format, 0, 0, desc.ArraySize);
    302     ComPtr<ID3D11RenderTargetView> rtv;
    303     const HRESULT hr = device->CreateRenderTargetView(texture.Get(), &rtv_desc, rtv.GetAddressOf());
    304     if (FAILED(hr)) [[unlikely]]
    305     {
    306       ERROR_LOG("Create RTV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
    307       return nullptr;
    308     }
    309 
    310     rtv_dsv = std::move(rtv);
    311   }
    312   else if (bind_flags & D3D11_BIND_DEPTH_STENCIL)
    313   {
    314     const D3D11_DSV_DIMENSION dsv_dimension =
    315       (desc.SampleDesc.Count > 1) ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
    316     const CD3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc(dsv_dimension, fm.dsv_format, 0, 0, desc.ArraySize);
    317     ComPtr<ID3D11DepthStencilView> dsv;
    318     const HRESULT hr = device->CreateDepthStencilView(texture.Get(), &dsv_desc, dsv.GetAddressOf());
    319     if (FAILED(hr)) [[unlikely]]
    320     {
    321       ERROR_LOG("Create DSV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
    322       return nullptr;
    323     }
    324 
    325     rtv_dsv = std::move(dsv);
    326   }
    327 
    328   ComPtr<ID3D11UnorderedAccessView> uav;
    329   if (bind_flags & D3D11_BIND_UNORDERED_ACCESS)
    330   {
    331     const D3D11_UAV_DIMENSION uav_dimension =
    332       (desc.ArraySize > 1 ? D3D11_UAV_DIMENSION_TEXTURE2DARRAY : D3D11_UAV_DIMENSION_TEXTURE2D);
    333     const CD3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc(uav_dimension, fm.srv_format, 0, 0, desc.ArraySize);
    334     const HRESULT hr = device->CreateUnorderedAccessView(texture.Get(), &uav_desc, uav.GetAddressOf());
    335     if (FAILED(hr)) [[unlikely]]
    336     {
    337       ERROR_LOG("Create UAV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
    338       return nullptr;
    339     }
    340   }
    341 
    342   return std::unique_ptr<D3D11Texture>(new D3D11Texture(width, height, layers, levels, samples, type, format,
    343                                                         std::move(texture), std::move(srv), std::move(rtv_dsv),
    344                                                         std::move(uav)));
    345 }
    346 
    347 D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
    348 {
    349 }
    350 
    351 D3D11TextureBuffer::~D3D11TextureBuffer() = default;
    352 
    353 bool D3D11TextureBuffer::CreateBuffer()
    354 {
    355   const u32 size_in_bytes = GetSizeInBytes();
    356   if (!m_buffer.Create(D3D11_BIND_SHADER_RESOURCE, size_in_bytes, size_in_bytes))
    357     return false;
    358 
    359   static constexpr std::array<DXGI_FORMAT, static_cast<u32>(Format::MaxCount)> dxgi_formats = {{
    360     DXGI_FORMAT_R16_UINT,
    361   }};
    362 
    363   CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(m_buffer.GetD3DBuffer(), dxgi_formats[static_cast<u32>(m_format)], 0,
    364                                             m_size_in_elements);
    365   const HRESULT hr =
    366     D3D11Device::GetD3DDevice()->CreateShaderResourceView(m_buffer.GetD3DBuffer(), &srv_desc, m_srv.GetAddressOf());
    367   if (FAILED(hr)) [[unlikely]]
    368   {
    369     ERROR_LOG("CreateShaderResourceView() failed: {:08X}", static_cast<unsigned>(hr));
    370     return false;
    371   }
    372 
    373   return true;
    374 }
    375 
    376 void* D3D11TextureBuffer::Map(u32 required_elements)
    377 {
    378   const u32 esize = GetElementSize(m_format);
    379   const auto res = m_buffer.Map(D3D11Device::GetD3DContext(), esize, esize * required_elements);
    380   m_current_position = res.index_aligned;
    381   return res.pointer;
    382 }
    383 
    384 void D3D11TextureBuffer::Unmap(u32 used_elements)
    385 {
    386   const u32 size = used_elements * GetElementSize(m_format);
    387   GPUDevice::GetStatistics().buffer_streamed += size;
    388   GPUDevice::GetStatistics().num_uploads++;
    389   m_buffer.Unmap(D3D11Device::GetD3DContext(), size);
    390 }
    391 
    392 void D3D11TextureBuffer::SetDebugName(std::string_view name)
    393 {
    394   SetD3DDebugObjectName(m_buffer.GetD3DBuffer(), name);
    395 }
    396 
    397 std::unique_ptr<GPUTextureBuffer> D3D11Device::CreateTextureBuffer(GPUTextureBuffer::Format format,
    398                                                                    u32 size_in_elements)
    399 {
    400   std::unique_ptr<D3D11TextureBuffer> tb = std::make_unique<D3D11TextureBuffer>(format, size_in_elements);
    401   if (!tb->CreateBuffer())
    402     tb.reset();
    403 
    404   return tb;
    405 }
    406 
    407 D3D11DownloadTexture::D3D11DownloadTexture(Microsoft::WRL::ComPtr<ID3D11Texture2D> tex, u32 width, u32 height,
    408                                            GPUTexture::Format format)
    409   : GPUDownloadTexture(width, height, format, false), m_texture(std::move(tex))
    410 {
    411 }
    412 
    413 D3D11DownloadTexture::~D3D11DownloadTexture()
    414 {
    415   if (IsMapped())
    416     D3D11DownloadTexture::Unmap();
    417 }
    418 
    419 std::unique_ptr<D3D11DownloadTexture> D3D11DownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format)
    420 {
    421   D3D11_TEXTURE2D_DESC desc = {};
    422   desc.Width = width;
    423   desc.Height = height;
    424   desc.Format = D3DCommon::GetFormatMapping(format).srv_format;
    425   desc.MipLevels = 1;
    426   desc.ArraySize = 1;
    427   desc.SampleDesc.Count = 1;
    428   desc.SampleDesc.Quality = 0;
    429   desc.Usage = D3D11_USAGE_STAGING;
    430   desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    431 
    432   Microsoft::WRL::ComPtr<ID3D11Texture2D> tex;
    433   HRESULT hr = D3D11Device::GetD3DDevice()->CreateTexture2D(&desc, nullptr, tex.GetAddressOf());
    434   if (FAILED(hr))
    435   {
    436     ERROR_LOG("CreateTexture2D() failed: {:08X}", hr);
    437     return {};
    438   }
    439 
    440   return std::unique_ptr<D3D11DownloadTexture>(new D3D11DownloadTexture(std::move(tex), width, height, format));
    441 }
    442 
    443 void D3D11DownloadTexture::CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width,
    444                                            u32 height, u32 src_layer, u32 src_level, bool use_transfer_pitch)
    445 {
    446   D3D11Texture* src11 = static_cast<D3D11Texture*>(src);
    447 
    448   DebugAssert(src11->GetFormat() == m_format);
    449   DebugAssert(src_level < src11->GetLevels());
    450   DebugAssert((src_x + width) <= src11->GetMipWidth(src_level) && (src_y + height) <= src11->GetMipHeight(src_level));
    451   DebugAssert((dst_x + width) <= m_width && (dst_y + height) <= m_height);
    452   DebugAssert((dst_x == 0 && dst_y == 0) || !use_transfer_pitch);
    453 
    454   ID3D11DeviceContext1* const ctx = D3D11Device::GetD3DContext();
    455   src11->CommitClear(ctx);
    456 
    457   D3D11Device::GetStatistics().num_downloads++;
    458 
    459   if (IsMapped())
    460     Unmap();
    461 
    462   // depth textures need to copy the whole thing..
    463   const u32 subresource = D3D11CalcSubresource(src_level, src_layer, src11->GetLevels());
    464   if (GPUTexture::IsDepthFormat(src11->GetFormat()))
    465   {
    466     ctx->CopySubresourceRegion(m_texture.Get(), 0, 0, 0, 0, src11->GetD3DTexture(), subresource, nullptr);
    467   }
    468   else
    469   {
    470     const CD3D11_BOX sbox(src_x, src_y, 0, src_x + width, src_y + height, 1);
    471     ctx->CopySubresourceRegion(m_texture.Get(), 0, dst_x, dst_y, 0, src11->GetD3DTexture(), subresource, &sbox);
    472   }
    473 
    474   m_needs_flush = true;
    475 }
    476 
    477 bool D3D11DownloadTexture::Map(u32 x, u32 y, u32 width, u32 height)
    478 {
    479   if (IsMapped())
    480     return true;
    481 
    482   D3D11_MAPPED_SUBRESOURCE sr;
    483   HRESULT hr = D3D11Device::GetD3DContext()->Map(m_texture.Get(), 0, D3D11_MAP_READ, 0, &sr);
    484   if (FAILED(hr))
    485   {
    486     ERROR_LOG("Map() failed: {:08X}", hr);
    487     return false;
    488   }
    489 
    490   m_map_pointer = static_cast<u8*>(sr.pData);
    491   m_current_pitch = sr.RowPitch;
    492   return true;
    493 }
    494 
    495 void D3D11DownloadTexture::Unmap()
    496 {
    497   if (!IsMapped())
    498     return;
    499 
    500   D3D11Device::GetD3DContext()->Unmap(m_texture.Get(), 0);
    501   m_map_pointer = nullptr;
    502 }
    503 
    504 void D3D11DownloadTexture::Flush()
    505 {
    506   if (!m_needs_flush)
    507     return;
    508 
    509   if (IsMapped())
    510     Unmap();
    511 
    512   // Handled when mapped.
    513 }
    514 
    515 void D3D11DownloadTexture::SetDebugName(std::string_view name)
    516 {
    517   if (name.empty())
    518     return;
    519 
    520   SetD3DDebugObjectName(m_texture.Get(), name);
    521 }
    522 
    523 std::unique_ptr<GPUDownloadTexture> D3D11Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format)
    524 {
    525   return D3D11DownloadTexture::Create(width, height, format);
    526 }
    527 
    528 std::unique_ptr<GPUDownloadTexture> D3D11Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
    529                                                                        void* memory, size_t memory_size,
    530                                                                        u32 memory_stride)
    531 {
    532   ERROR_LOG("D3D11 cannot import memory for download textures");
    533   return {};
    534 }